2011-06-28 43 views
1

最近有人建議我刪除僅用於存儲ID的自動遞增表。我還沒有走這個,我只是在探索它是否實際上是a better solution than what I currently have。這將使我有這樣的一個表:處理非自動遞增ID的策略

create table tag_translations (
    tag_id int not null, 
    language_id int not null, 
    tag_name varchar(255), 
    primary key (tag_id, language_id) 
); 

我將有TAG_ID複製,存儲在其他語言標籤的翻譯。

添加新標籤時,我需要放棄在tag_id上使用自動增量,而是手動分配新ID。除非它只是對現有標籤的翻譯,否則該標識對於新批次的翻譯插入內容必須是唯一的。

有人能用簡單的英語向我解釋這是如何典型地完成的嗎?我想到了這一點,但如果我的想法正確的話,它似乎沒有比我以前的方法更清潔。這裏就是我假設的過程是:

  • 從tag_translations選擇TAG_ID
  • 選擇在結果集中+ 1
  • 最多做一個新的查詢(插入)
  • 定義一些額外的確保在新標籤記錄的ID不會重複的情況下,標籤的創建時間差不多相同微秒

如果這是一個過程,我認爲我最好堅持使用現有的s chema有一個額外的表來自動增加id。我仍然需要做一個額外的查詢,以便首先檢查一個唯一的ID(我今天正在交易一個單一的連接)。如果我想讓自己的身份標識獨一無二的頭痛是我的想法,那麼我可能會放棄這種方法並堅持我所擁有的。我的想法是什麼?

回答

2

爲了生成新的標籤ID,有一個比select max(tag_id) + 1更好的選項。你可以用一個字段模仿MySQL中的序列/生成器,並使用last_insert_id()的參數。下面創建序列:

create table tag_id_seq (id int not null default 0); 
insert into tag_id_seq values (0); 

創建序列後,你可以從它那裏得到了一張ID與2條語句是這樣的:

update tag_id_seq set id = last_insert_id(id + 1); 
select last_insert_id(); 

last_insert_id()是連接特定的,所以基本上第一個語句用於僅捕獲執行它的連接的值,並更新序列。第二條語句只是檢索值。如果兩個不同的連接的更新聲明彼此非常接近,他們都會在last_insert_id()中隱藏不同的ID。

您可以將其封裝在僅傳遞序列名稱的函數中,然後在您真正創建新標籤時調用它。這會比您的tags表具有單個auto_increment列更好。

而是開始0下一個ID爲1,你可以與目前使用的ID把它連:

update tag_id_seq set id = (select coalesc(max(tag_id),0) from tag_translations); 

也有對update聲明的變化:

  • 一些喜歡讓id字段代表下一個ID應該是什麼,而不是最後一個ID是什麼。在這種情況下,你會開始id1,而不是0,如果它是一個新的序列,並使用set id = last_insert_id(id) + 1(與外部加)。
  • 此外,有些情況下一次需要「保留」幾個新ID,而不是1。在這種情況下,你會添加無論你需要多少。基於上述變化,讓我們說的順序是11,意味着檢索的最後id1011是下一個ID。如果您需要7個新ID,您可以使用set id = last_insert_id(id) + 711已被select last_insert_id()收回,這意味着您將使用ID 1117(含)。該序列將更新爲18,這是將要檢索的下一個ID。

序列在許多情況下的優勢,而這些有幾個:

  • 複合鍵不能包含auto_increment列,但你仍然需要一種方法來生成的ID。
  • 關於這種在MySQL中執行序列的重要的事情是該領域。這意味着您可以將字段包含當前/下一個序列值幾乎任何地方。

    例如,代替具有用於每個序列幾十個表,1,可以創建與1列處的序列名稱和當前/下一個值字段1列中的序列表。在1個表中的行數十種更爲整潔:

    create table sequences (
        seqname varchar(50) primary key, 
        id int not null default 0); 
    

    (如果該表是InnoDB的,行級鎖而不是使用表鎖。)

  • auto_increment in InnoDB可能不會在行爲方式你喜歡。在啓動時,它將執行相當於select max(id)+1的重置計數器。這可能會導致倒帶和重新使用以前使用過的ID。

+0

哎喬爾,非常感謝。問題是,你是不是在這裏創建一個表格(tag_id_seq)? –

+0

@Calvin:是的,在我的例子中創建了一個表格,但它只有1列和1行。一個序列的重要部分並不是把整個表都用到它上面,而是更新一個字段。您可以將序列字段隱藏在其他地方,例如像這樣的表格,每個序列都有一行:'create table(seq_name varchar(20)not null,id int not null)'(InnoDB表使用行 - 級別鎖定)。我已經使用了所需的任何實現。 –

+0

這比擁有一個自動增量的額外表格(也有1列和1行)更簡單嗎?這是prompte這一個的問題:http://stackoverflow.com/questions/6481505/one-column-sql-table-the-column-being-an-id-is-this-crazy –