2013-03-25 64 views
0

我有一個獨特的PK'id',它被設置爲auto_increment。我有第二個叫做'label'的字段,它是一個字母數字字段(例如W1000),用於使用PHP邏輯在每個插入上遞增。多個auto_increment字段

「標籤」字段可能包含許多字母前綴之一,後跟增加的數字。每個前綴應該獨立增加。例如,表格可能有W1000和F1123。下一個W將是W1001,下一個F將是F1124。

當前方法(PHP選擇最大標籤,插入最大標籤+1)會創建一個競爭條件,偶爾會得到一個重複的「標籤」。我需要解決這些重複的「標籤」,並確保此字段是唯一的。如果有幫助,我願意將前綴和數字分成兩個字段。

完成此操作的最佳方法是什麼?

+0

將字段設置爲'UNIQUE'? – hjpotter92 2013-03-25 02:00:54

回答

1

避免生成重複標籤值的一種方法是使用MyISAM表來生成唯一的序列號。 MyISAM支持您需要的AUTO_INCREMENT行爲。

參見「MyISAM的注意事項」一節中的MySQL參考3.6.9. Using AUTO_INCREMENT

對於這種方法,你可以創建一個單獨的MyISAM表;該表的目的是生成唯一的序列號:例如,

CREATE TABLE foo 
(prefix VARHCAR(1) NOT NULL 
, num  INT UNSIGNED AUTO_INCREMENT 
, PRIMARY KEY (prefix, num) 
) Engine=MyISAM 

假設標籤前綴是一個字符,其餘是數字:

INSERT INTO foo (prefix, num) 
SELECT SUBSTR(t.label,1,1) AS prefix 
    , MAX(SUBSTR(t.label,2,8) AS num 
    FROM mytable 
GROUP BY SUBSTR(t.label,1,1) 

去獲得新的序列號,插入一行到新表,爲前綴的值,併爲NUM列NULL,並檢索插入的Num列的值:

INSERT INTO foo (prefix,num) VALUES ('W',NULL); 
SELECT LAST_INSERT_ID(); 

你可以用它來構建的價值在你用於label列r原始表格。

請注意,它只是具有所需行爲的MyISAM引擎(爲每個前綴分別增加AUTO_INCREMENT序列)。您的原始表可以是任何引擎。

這種方法避免了競爭條件,但是由於在MyISAM表上插入了獨佔鎖,所以引入了併發瓶頸。


的另一種方式,以避免競態條件是獲得對錶的排他鎖,然後做一個SELECT MAX(),然後執行插入,然後鬆開該鎖。但是這種方法引入了更多的併發瓶頸,即對單個資源的訪問序列化。


如果你的問題是關於識別重複的現有label值,那麼這個查詢獲取你有「重複」標籤的行。 (這是挑選出只有一行,每個重複的標籤。)

SELECT t.label 
    , MAX(t.id) 
    FROM mytable t 
GROUP BY t.label 
HAVING COUNT(1) > 1 

要更新標籤是唯一的,你需要生成這些行的新標籤。

在單個SQL語句中完成該操作有點棘手。我試圖提出一個聲明,但它被破壞了,我沒有時間去修復它。