问题描述
我的应用程序需要一个带有自动增量主键列且没有间隙的表。正如其他人所指出的,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 个结论:
-
这里提到的用例并不恰当。 (没有理由期待性能提升;也许恰恰相反。)但是,
-
如果您的数据模型需要无间隙的升序数字,最好自己实现。
谢谢大家
,我想象表单的范围查询
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 的实现也可能无法保证不会出现间隙。