我有一个MySQL表,其中id
是主键并自动递增。
由于我有一个使用ON DUPLICATE KEY
每分钟运行一次cron作业(通过外部API更新统计信息),因此我在id
列中发现了很多空白。我设置了一个唯一的列,这显然是造成差距的原因。
例如,只有183行,但是我已经在id
列上了71511。
我运行的唯一SELECT查询与此类似:
SELECT * FROM table WHERE member = '123' ORDER BY id DESC LIMIT 30
我不在乎这个数字正在迅速增加,并且没有在其他任何地方使用。我只是想找出它是否会导致查询随时间推移变慢。
例如,如果我有一个具有100,000行的表,但是id
处于十亿行,那么间隙会导致插入或选择的运行速度变慢吗?
答案 0 :(得分:2)
不,存在差距因为,通过这种方式计算唯一标识符可以更快,更轻松地处理并发系统。
auto_increment的值是1
还是755131
与性能无关。
存储要求由您的表定义,自动增量的最常用存储标识符是4字节int
。无论您存储什么数字,它都会占用4个字节(如果可以容纳4个字节的话)。
存在差距的原因是存在的,为什么它们不是问题。 Primary key
是唯一标识符。计算唯一标识符的最简单方法是每次对表进行更改(插入,删除)时都增加一个数字。
此数字不是必需的顺序,而是唯一的。 MySQL使用顺序算法来计算唯一数字。
由于MySQL考虑到并发操作,因此每个事务都是隔离的(如果使用事务引擎)。如果事务引起对auto_increment的更改但未能记下,则auto_increment将永远花费。每个表只有一个计数器,没有代码检查该数字是否应该减少(这是浪费资源)-无论查询是否成功,它都只会增加。
这种方法保证:
性能-无需担心计数器的状态应该是什么(是否应该下降)
唯一性-这是计算行的唯一标识符的最快,最安全的方法-只需将数字增加auto_increment_offset
。无需担心碰撞,什么也不担心。您可以100%确信,如果将最后一个数字加auto_increment_offset
,则会在数据库中获得一个新的,唯一的且未使用的数字/
对于数据库,尤其是MySQL,在读写性能方面有多种因素。最小最大化和尝试摆弄auto_increment
并不是其中之一。如果一切都保持不变,您会没事的。
如果您认为将超过4字节无符号整数的最大值(大约42亿美元),则可以考虑将主键更改为bigint
。如果您每秒要插入数千条记录,那么您将不会超过数千年。
答案 1 :(得分:1)
通常,我会说这不是问题。但是,这引起了我的注意:
例如,只有183行,但我的id列已经在71511。
这是很多的空白。造成差距的通常原因是删除和插入失败(在其他数据库中,为了提高效率分配id块)。
您似乎了解这些差距。您可以在插入时稍稍用手即可消除它们:
insert into t ( . . . )
select . . . --values here
from dual
where not exists (select 1 from t t2 where . . .) -- duplicate key catch here
on duplicate key . . .;
仅在出现竞争情况时才需要重复密钥-where
将在insert
之前 消除大多数或全部密钥。这可能会消除所有差距。
对于具有100,000行的表必须使用bigint远非优雅。大整数将索引的大小加倍。它们增加了每个页面上的记录所需的存储量。增加数据库的大小会增加I / O开销。