这里的问题与我曾经提出的另一个问题有关...我有数百万条记录,每个记录的ID都是自动增加的,但不幸的是,有时会丢弃生成的ID,因此ID之间存在许多空缺。 我想找到这些空缺,并重新使用被抛弃的ID。在MySQL中有效完成这项任务的方法是什么?
首先,您试图通过重用跳过的值获得什么优势?普通的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后,可以随时再次运行它。/* 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;
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);