5

这里的问题与我遇到的另一个问题有关...

我有数百万条记录,每条记录的 ID 都是自动递增的,不幸的是,有时生成的 ID 有时会被丢弃,因此 ID 之间有很多差距。

我想找到差距,并重新使用被遗弃的 id。

在 MySQL 中执行此操作的有效方法是什么?

4

4 回答 4

17

首先,您想通过重用跳过的值来获得什么优势?一个普通的INT UNSIGNED会让你数到 4,294,967,295。有了“数百万条记录”,您的数据库必须增长一千倍,然后才能用完有效的 ID。(然后使用 aBIGINT 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,你总是可以再次运行它。

于 2011-12-09T18:07:43.257 回答
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;
于 2012-12-30T17:52:35.950 回答
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);
于 2013-06-17T13:26:55.747 回答
0

如果您使用的MariaDB是一个更快的选项

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

文档:https ://mariadb.com/kb/en/mariadb/sequence/

于 2017-01-10T14:33:50.660 回答