如何在 MySQL 记录集中找到 ID 间隙?
Posted
技术标签:
【中文标题】如何在 MySQL 记录集中找到 ID 间隙?【英文标题】:How can you find ID gaps in a MySQL recordset? 【发布时间】:2011-12-09 17:58:11 【问题描述】:这里的问题与我的另一个问题有关......
我有数百万条记录,每条记录的 ID 都是自动递增的,不幸的是,有时生成的 ID 有时会被丢弃,因此 ID 之间有很多差距。
我想找到差距,并重新使用被放弃的 id。
在 mysql 中执行此操作的有效方法是什么?
【问题讨论】:
相关:***.com/questions/3718229/… 如果您使用 INT 作为主键,您可以拥有超过 20 亿条记录。为什么要努力填补空白?你的号码用完了吗?我发现知道数字与添加记录的顺序相对应是有好处的。 与尝试在非常大的表上重用 ID 相比,将主键类型更改为 BIGINT(如果 INT 提供的 4 十亿值太短)可能会减少性能问题。跨度> +1 以获得良好的反馈。我没有考虑过也许最好不要担心这些差距。 其他一些人在您有重用废弃 ID(在某些情况下属于死者的公民身份号码)的想法之前,这个“精明”的决定会给继承重用 ID 的人带来无穷无尽的问题.我不建议以任何方式做这样的事情。 【参考方案1】:首先,您想通过重用跳过的值来获得什么优势?一个普通的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 是第一个间隙,则不会返回 在我的情况下,每个缺失的数字都很重要,答案的最后一段也很重要:) +1 Upvote【参考方案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;
【讨论】:
第二个查询''select cs.n as bchain, ce.n as echain from cs,ce where cs.row=ce.row;''这个join就显示出实际存在的较大差距但是第一个效果很好。【参考方案3】:此解决方案更好,以防您需要将第一个元素包含为 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);
【讨论】:
【参考方案4】:如果您使用的是MariaDB
,您有更快的选择
SELECT * FROM seq_1_to_50000 where seq not in (select col from table);
文档:https://mariadb.com/kb/en/mariadb/sequence/
【讨论】:
以上是关于如何在 MySQL 记录集中找到 ID 间隙?的主要内容,如果未能解决你的问题,请参考以下文章