ここでの問題は、私が持っていた別の質問に関連しています...
私は何百万ものレコードを持っていますが、それらの各レコードのIDは自動的にインクリメントされますが、残念ながら、生成されたIDが破棄されることがあるため、ID間には多くのギャップがあります。
ギャップを見つけて、放棄されたIDを再利用したいと思います。
MySQLでこれを行うための効率的な方法は何ですか?
ここでの問題は、私が持っていた別の質問に関連しています...
私は何百万ものレコードを持っていますが、それらの各レコードのIDは自動的にインクリメントされますが、残念ながら、生成されたIDが破棄されることがあるため、ID間には多くのギャップがあります。
ギャップを見つけて、放棄されたIDを再利用したいと思います。
MySQLでこれを行うための効率的な方法は何ですか?
まず、スキップされた値を再利用することでどのような利点を得ようとしていますか?普通INT UNSIGNED
なら4,294,967,295まで数えることができます。「数百万のレコード」を使用すると、有効なIDがなくなる前に、データベースを1000倍に増やす必要があります。(そして、を使用する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を入力すると、いつでも再度実行できます。
以下は、mytabの整数フィールド「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;
最初の要素を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);
を使用しているMariaDB
場合は、より高速なオプションがあります
SELECT * FROM seq_1_to_50000 where seq not in (select col from table);