2011-12-09 4 views
5

ここでの問題は、私が持っていた別の質問に関連している...MySQLレコードセットでIDギャップを見つける方法はありますか?

私は数百万レコードを持っており、それらのレコードのそれぞれのIDが自動インクリメントされ、生成された残念ながら、時にはIDは時々そう捨てられID間には多くのギャップがあります。

ギャップを見つけて、放棄されたIDを再利用したいと思います。

MySQLで効率的な方法は何ですか?

+0

関連:http://stackoverflow.com/questions/3718229/stop-mysql-reusing-auto-increment-ids –

+2

主キーにINTを使用している場合は、20億件以上のレコードを持つことができます。ギャップを埋めようとするのはどうですか?あなたは番号が不足していますか?私は、数字がレコードが追加された順番に対応していることを知ることに利点があることが分かりました。 – minboost

+1

非常に大きなテーブルのIDを再利用しようとするよりも、プライマリキーのタイプをBIGINT(INTが提供する4つの金額が短すぎる場合)に変更すると、パフォーマンスが低下することがあります。 –

答えて

17

まず、スキップされた値を再利用することでどのようなメリットが得られますか?通常のINT UNSIGNEDは、4,294,967,295まで数えます。 「数百万のレコード」を使用すると、データベースは有効なIDがなくなる前に何千倍も成長する必要があります。 (そしてBIGINT UNSIGNEDを使用すると、18,446,744,073,709,551,615値にあなたをバンプされます。)

は、MySQLがスキップされた値を再利用しようとすると、実際にMySQLを気にしない何かを補うためにしようと、あなたの時間の多くを使用する可能性があります最初の場所。

ということで、あなたのような何かをIDを欠けて見つけることができます:

SELECT id + 1 
FROM the_table 
WHERE NOT EXISTS (SELECT 1 FROM the_table t2 WHERE t2.id = the_table.id + 1); 

これは、各シーケンス(あなたは{1, 2, 3, 8, 10}を持っている場合例えば、それは{4,9}があります)でのみ最初欠番がありますが、それは効率的である可能性が高く、IDを入力した後は、いつでもそれを再度実行することができます。

+1

thouroughと思慮深い答えのための+1 – qodeninja

+0

1が最初のギャップであれば返されません – morandi3

+0

私の場合、それぞれの欠けている数字は重要ですので、答えの最後の段落です:+1 Upvote – AamirR

2

Myタブに整数フィールドの「n」の各ギャップの行が返されます、次の代わりにギャップのあなたが連続したチェーンをしたい場合は

/* cs will contain 1 row for each contiguous sequence of integers in mytab.n 
    and will have the start of that chain. 
    ce will contain the end of that chain */ 
create temporary table cs (row int auto_increment primary key, n int); 
create temporary table ce like cs; 
insert into cs (n) select n from mytab where n-1 not in (select n from mytab) order by n; 
insert into ce (n) select n from mytab where n+1 not in (select n from mytab) order by n; 
select ce.n + 1 as bgap, cs.n - 1 as egap 
    from cs, ce where cs.row = ce.row + 1; 

は、最終的な選択は次のようになります。

select cs.n as bchain, ce.n as echain from cs,ce where cs.row=ce.row; 
+0

2番目のクエリ ''選択cs.nはチェスとして、チェンはチェスからセクとして、cs.row = ce.rowのように、実際に存在する大きなギャップを表示するには結合しますが、最初のものはうまくいきます。 – magdmartin

1

このソリューションは、あなたが1として最初の要素を含める必要がある場合には、優れている:

SELECT 
    1 AS gap_start, 
    MIN(e.id) - 1 AS gap_end 
FROM 
    factura_entrada e 
WHERE 
    NOT EXISTS(
     SELECT 
      1 
     FROM 
      factura_entrada 
     WHERE 
      id = 1 
    ) 
LIMIT 1 
UNION 
    SELECT 
     a.id + 1 AS gap_start, 
     MIN(b.id)- 1 AS gap_end 
    FROM 
     factura_entrada AS a, 
     factura_entrada AS b 
    WHERE 
     a.id < b.id 
    GROUP BY 
     a.id 
    HAVING 
     gap_start < MIN(b.id); 
0

あなたがMariaDBを使用している場合は、より高速なオプションがあり

SELECT * FROM seq_1_to_50000 where seq not in (select col from table); 

ドキュメント:https://mariadb.com/kb/en/mariadb/sequence/

関連する問題