这里的问题与我的另一个问题有关......
我有数百万条记录,每条记录的ID都是自动递增的,不幸的是,有时候生成的ID有时会被丢弃,因此ID之间存在很多差距。
我想找到差距,并重新使用被放弃的ID。
在MySQL中执行此操作的有效方法是什么?
答案 0 :(得分:17)
首先,你试图通过重用跳过的值来获得什么优势?一个普通的INT UNSIGNED
会让你数到4,294,967,295。使用“数百万条记录”,您的数据库必须在用完有效ID之前增长一千倍。 (然后使用BIGINT UNSIGNED
会使您达到18,446,744,073,709,551,615个值。)
尝试回收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 :(得分:2)
以下内容将为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;
答案 2 :(得分: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);
答案 3 :(得分:0)
如果您使用的是MariaDB
,则可以选择更快的选项
SELECT * FROM seq_1_to_50000 where seq not in (select col from table);