没有间隙的 SQL 自动增量——解决方法/最佳实践

问题描述

我的应用程序需要一个带有自动增量主键列且没有间隙的表。正如其他人所指出的,AUTOINCREMENT 实现通常会导致间隙(txn 回滚、删除等)。没有间隙的自动增量在应用程序层很容易实现,但我想知道是否有更好的(更 sql 的)方法解决这个问题。

我喜欢没有间隙的原因是因为我想象了表单的范围查询

SELECT * 
FROM chainTable 
WHERE chn_id >= 10005003 AND chn_id <= 10005009

比表单查询更快

SELECT * 
FROM chainTable 
WHERE chn_id >= 10005003 
ORDER BY chn_id 
LIMIT 7

在我的应用程序中,选定的行是在同一个事务中创建的。因此,我需要在同一交易中生成的值不能有任何差距。所以我的问题归结为:

在事务生成的 AUTOINCREMENT 列值是否保证是连续的(即没有间隙)?

我的猜测仍然是“不”,但我很想错。

解决方法

在应用程序中管理 id 的开销将比让您的 sql 引擎处理它更昂贵。

对于您的查询,只要您在该列上有适当的索引,就不会有明显的性能差异。 但是第二个查询可能会稍微快一点,因为它只需要检查一个条件。

,

从您的评论/回答得出的 2 个结论:

  1. 这里提到的用例并不恰当。 (没有理由期待性能提升;也许恰恰相反。)但是,

  2. 如果您的数据模型需要无间隙的升序数字,最好自己实现。

谢谢大家

,

我想象表单的范围查询

SELECT * 
FROM chainTable 
WHERE chn_id >= 10005003 AND chn_id <= 10005009

比表单查询更快

SELECT * 
FROM chainTable 
WHERE chn_id >= 10005003 
ORDER BY chn_id 
LIMIT 7

你应该先尝试证明这一点。如果索引用于 chn_id,我认为第一种形式不会更快。

如果使用索引,则行将按索引顺序读取,因此 ORDER BY chn_id 是空操作。 MySQL 已经按照 chn_id 的索引顺序读取行,因此它只会在范围开始后继续读取前 7 行,然后由于 LIMIT 而停止。

我认为您不需要一个解决方案来使您的 auto-inc 连续(即没有间隙)。

为了记录,在事务中自动递增肯定不是连续的。如果是,那么一个事务将阻止其他会话插入数据。

我的表应该是分类帐(仅限追加),行号在数据模型中占据显着位置。

自动增量不是行号。不要尝试将其用作行号。

如果您回滚或删除行,您将始终存在间隙。或者,如果 INSERT 由于错误(例如违反约束)而失败。此外,根据您使用的 RDBMS 品牌,即使在正常使用情况下,auto-inc 的实现也可能无法保证不会出现间隙。