2011-04-19 2 views
6

오늘 저는 내가 본 MySQL 중에서 가장 이상한 것을 발견했습니다. 나는 자바와 MySQL의 커넥터 - 자바 - 5.1.15 라이브러리 내부에 데이터를 삽입하고mysql auto_increment 열이 무작위 값으로 증가합니다

CREATE TABLE `features` 
(
    `feature_id` mediumint(6) unsigned NOT NULL AUTO_INCREMENT, 
    `feature_name` varchar(100) CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL, 
    PRIMARY KEY (`feature_id`), 
    UNIQUE KEY `feature_name_key` (`feature_name`) 
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci; 

: 나는 사소한 테이블이 있습니다. feature_name의 데이터가 중복 될 수 있으며 고유 한 값만 원할 것입니다. 데이터가 DB에 삽입 한 후

pstmt = conn.prepareStatement( 
     "INSERT INTO features (feature_name) VALUES (?)"); 

for (String featureName: data4db.keySet()) 
{ 
    pstmt.setString(1, featureName); 

    try 
    { 
     pstmt.executeUpdate(); 
    } 
    catch (SQLException se) 
    { 
     if (se.getErrorCode() == 1062) // duplicate entry 
     { 
      continue; // ignore 
     } 

     throw se; // do not ignore anything else 
    } 
} 

내가조차 예상하지 한 몇 가지 문제가 있었다 것으로 나타났습니다 : 긴 나는 그래서이 사용을 간과 할 수 나는 무시 INSERT를 사용할 수 있지만 경우에 데이터가 너무 . 위의 표에는 대략 4000 개의 레코드가 있는데, 이는 ok입니다. 유일한 문제는 중복 된 기본 키로 인해 일부 데이터를 삽입 할 수 없으므로이 테이블에 대한 자동 inc 값의 모양을 살펴 보았습니다. 대부분의 데이터에서 인접한 다음 행의 ID가 예상대로 1 씩 증가했습니다. 나는 때때로 feature_id가 3, 5, 1000, 100000- 완전히 무작위로 증가했다는 것을 알지 못합니다. 따라서 일단 id가 중간 값의 int에 대해 최대 값에 도달하면 삽입 할 수 없으므로이 테이블에서 '부족한 위치에 있습니다.

어떻게 이런 일이 발생할 수 있습니까? 비슷한 사람이 있습니까? 하나의 스레드가이 테이블에 쓰는 프로그램이 하나만 있다고 말할 가치가 있습니다. 저는 테이블이 거의 동일합니다 - 열 너비와 이름이 다릅니다. 이것에 대해서도 비슷한 문제가 있습니다. BTW

- 좀 더 데이터 :

mysql> show global variables like 'auto_inc%'; 
+--------------------------+-------+ 
| Variable_name   | Value | 
+--------------------------+-------+ 
| auto_increment_increment | 1  | 
| auto_increment_offset | 1  | 
+--------------------------+-------+ 
2 rows in set (0.01 sec) 

mysql> show global variables like 'ver%'; 
+-------------------------+------------------------------+ 
| Variable_name   | Value      | 
+-------------------------+------------------------------+ 
| version     | 5.5.10      | 
| version_comment   | MySQL Community Server (GPL) | 
| version_compile_machine | x86       | 
| version_compile_os  | Win32      | 
+-------------------------+------------------------------+ 

사전에 어떤 힌트를 주셔서 감사합니다.

답변

10

정상적인 MySQL 동작입니다. 다음 상황이 발생했습니다 : auto_increment key 3까지 데이터를 삽입 한 다음 feature_name_key가 고유하게 정의되어 있기 때문에 중복 키를 얻었습니다. MySQL은 정수 4를 "낭비"하고 다음 키로 이동합니다. 키 제약으로 인해 쓰기에 실패한 정수를 다시 사용하지 않습니다.

PK | feature_name_key 
1 | key1 
2 | key2 
3 | key3 
4 | key1 (fails due to constraint, 4 is not going to be used for next successful insertion, hence the gaps in your primary key) 

는 다음 기본 키/AUTO_INCREMENT에 해당하는 정수에 잃을 :

당신이 뭔가를 가지고 있다면. 데이터를 보관할 테이블을 삽입하거나 구성하는 동안 전략을 다시 생각해보십시오.

+0

맞습니다. 신속하고 유용한 교훈을 주셔서 감사합니다. 나는 그것을 두 번 점검했다. 따라서 근본적으로 2 개의 인접한 행에있는 ID 간의 차이 인 숫자는이 2 개의 행 사이에 중복 삽입 시도가 몇 번 있었는지를 나타냅니다. – Artur

+0

복제본이 어떻게 든 비활성화되면 자동 증가가 가능합니까? 해결 방법이 있습니까? 난 그냥 ID와 어떤 ID를 갭이 할당 된 고유 한 문자열을 가진 테이블을 가지고 싶지만 삽입을 사용하지 않으려는 ignore (autoinc와 동일한 문제가 있음) 또는 어떤 값이 이미 있는지 확인하기 위해 삽입하기 전에 전체 테이블을 읽지 않습니다. 그곳에? 절차? – Artur

+0

많은 해결 방법이 있지만 질문은 - 왜 순차적 ID를 원합니까? 자연의 열쇠가 이론의 관점에서 훨씬 더 나은 선택이 될 때 여기에서 대리 키를 사용합니다. feature_name_key를 기본 키로 사용할 수 있으므로 (고유 제한이 즉시 시행됨) sequence_id라는 컬럼을 업데이트하는 트리거를 작성한 다음 특성 이름에 간격없이 순차적으로 정수를 할당 할 수 있습니다. –

0

삽입 사이에 행을 삭제 했습니까? MySQL은 단순히 자동 증가 카운터를 기억하고 있습니다.

+0

삽입이 없습니다 - 이미 답변을 알고 있습니다 - 고맙습니다. – Artur

관련 문제