2011-04-19 98 views
6

今天我遇到了我見過的MySQL中最奇怪的事情之一。 我有一個簡單的表: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; 

我裏面與Java和MySQL連接器的Java-5.1.15庫插入數據。 feature_name中的數據可能會重複,我只想要唯一的值。我可以使用INSERT忽略,但如果數據太長我可能會忽略它,所以我用這個:

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 
    } 
} 

數據已經被插入到數據庫後,我發現有一些問題,我還沒有甚至有望。上表中大概有4000條記錄可以。唯一的問題是由於重複主鍵導致一些數據無法插入,所以我查看了這個表的auto inc值的外觀。事實證明,對於大多數數據,下一個相鄰行的id按預期遞增1。由於原因,我不知道有時feature_id增加了3,5,1000,100000 - 完全隨機的值。因此,我'在這個表中不合適的位置',因爲一旦id達到中等int的最大值,它就不能被插入。

這是怎麼發生的? 有沒有人遇到過類似的東西? 值得一提的是,只有一個程序只有一個線程寫入此表。 我'有更多的表幾乎相同 - 列的寬度和名稱是不同的。對於這一個也有類似的問題。

順便說一句 - 一些數據:

​​

謝謝你的任何提示提前。

回答

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

你是對的。感謝同學們的快速和非常有用的教訓。我已經仔細檢查過它。因此,基本上數字是兩個相鄰行中的ID之間的差異,表示在這兩行之間存在多少次重複插入嘗試。 – Artur 2011-04-19 09:19:41

+0

當重複發現被禁用時會自動增加嗎?有解決方法嗎?我只想擁有一個帶有id和一些唯一字符串的表,並且沒有id空位,但不想使用insert ignore(它與autoinc有相同的問題),也不會在插入之前讀取整個表以檢查哪些值已經存在那裏?程序? – Artur 2011-04-19 09:28:38

+0

有很多解決方法,但問題是 - 爲什麼你需要順序ID?你在這裏使用代理鍵時,從理論的角度來看,自然鍵將是更好的選擇。您可以將您的feature_name_key作爲主鍵(因此可以立即執行唯一約束),並且您可以創建一個觸發器來更新名爲sequence_id的列,然後可以按順序指定整數,而無間隙地分配給您的功能名稱。 – 2011-04-19 09:41:57

0

在你的插入之間,你有刪除行嗎? MySQL可能只是記住自動增量計數器。

+0

沒有插入只 - 我知道答案已經 - 謝謝 – Artur 2011-04-19 09:23:57