2011-06-28 14 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を手動で割り当てる必要があります。既存のタグの単なる翻訳でない限り、IDは翻訳された挿入の新しいバッチに対して一意である必要があります。

誰かが私に普通の英語で説明することができますか?私はこれについて考えましたが、もし私が思考の権利を持っていれば、私の以前のアプローチよりもきれいではないようです。ここで私はプロセスがあると仮定していますものです:

  • tag_translations
  • から選択TAG_IDは、結果セット+ 1
  • で最も数が(挿入するための)新しいクエリを作成します選ん
  • いくつかの追加を定義します。新しいタグIDレコードのIDが重複しないようにするための戦略

これがプロセスであれば、私は既存のものchemaは、自動インクリメントIDの追加テーブルを持っています。私はまだユニークなIDをチェックするために追加のクエリを実行する必要があります(私は今日、インサートのために単一の参加をトレードしています)。私のIDをユニークにする必要があるときにユニークなIDを保持するという頭痛があるとすれば、私はこのアプローチを放棄して、私が持っているものに固執したいと思うかもしれません。私の考えは響きますか?

答えて

2

新しいタグIDを生成する場合は、select max(tag_id) + 1よりも優れたオプションがあります。 1つのフィールドでMySQLのシーケンス/ジェネレータを模倣し、last_insert_id()の引数を使用することができます。以下は、シーケンスを作成します。シーケンスを作成した後

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

、あなたはこのような2文でそれから次のIDを取得することができます:

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

last_insert_id()接続固有のものであるため、基本的に最初の文シーケンスを更新するだけでなく、それを実行した接続のみの値を取得するために使用されます。 2番目のステートメントは値を取得するだけです。 2つの異なる接続が更新ステートメントを互いに非常に近いものにした場合、それらは両方とも依然としてlast_insert_id()に詰め込まれた異なるIDを持ちます。

単純にシーケンス名を渡して、実際に新しいタグを作成しているときに呼び出すことができます。これは、単一のauto_increment列を持つtagsテーブルよりも優れています。代わりに、次のIDが1であると0から始まるの

、あなたは現在使用されてIDを持つも、それを持ち出すことができます。

  • 一部:

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

    することもupdateステートメントのバリエーションがありますidフィールドに、最後に与えられたIDが何であったかではなく、次のIDが何であるべきかを表すようにします。その場合、0の代わりに1としてidを開始し、新しいシーケンスの場合はset id = last_insert_id(id) + 1(外側に追加する)を使用します。

  • また、状況によっては、一度に1つではなく複数の新しいIDを「予約する」こともあります。その場合、必要な数を追加します。上記のバリエーションに基づいて、シーケンスが11にあり、最後にidが取得されたことが10であり、11が次のidであるとします。 7つの新しいIDが必要な場合は、set id = last_insert_id(id) + 7を使用します。 11select last_insert_id()となります。つまり、ids 1117(両端を含む)を使用します。シーケンスは、検索される次のIDである18に更新されます。

の配列は、多くの状況での利点を有し、これらはいくつかある:

  • 複合キーが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行しかありません。シーケンスの重要な部分は、テーブル全体を強調するのではなく、単一のフィールドを更新することです。このようなテーブルのように、シーケンスフィールドをそれぞれのシーケンスに対して1つの行で置き換えることができます: 'create table(seq_name varchar(20)not null、id int not null)'(InnoDBテーブルではrow-レベルロック)。私はどんな実装でも必要な状況を使用しました。 –

+0

これは、自動増分する余分なテーブル(1列と1行も含む)を持つよりも簡単ですか?これは、これを促す質問です:http://stackoverflow.com/questions/6481505/one-column-sql-table-the-column-being-an-id-is-this-crazy –

関連する問題