[英]Indexed column and not indexed column research
我生成了单独的 MySQL Innodb 表,其中包含 2000、5000、10000、50000、10000、20000、50000、100 000、200 000 个元素(借助 php 循环和插入查询)。 每个表有两列:id(Primary Key INT autoincrement)、number(INT UNIQUE KEY)。 然后我做了同样的但这次我生成了类似的表,其中number列没有 INDEX 。我以这样的方式生成表:列号的值等于索引值 + 2:第一个元素 == 3,第 1000 个元素是 1002,依此类推。 我想测试这样的查询,因为它将在我的应用程序中使用:
SELECT count(number) FROM number_two_hundred_I WHERE number=200002;
在为这些表生成数据后,我想测试最坏情况查询的时间。 我使用了显示配置文件。 我假设最坏情况的查询将对应于列号值为 1002、2002 等的元素,所以这里是我测试的所有查询和时间(由 SHOW PROFILES 评估):
SELECT count(number) FROM number_two_thousand_I WHERE number=2002;
// for tables with indexed column number I used **suffix _I** in the end
// of name of the table. Here is the time for it 0.00099250
SELECT count(number) FROM number_two_thousand WHERE number=2002;
// column number is not indexed when there is no **suffix _I**
// time for this one is 0.00226275
SELECT count(number) FROM number_five_thousand_I WHERE number=5002;
// 0.00095600
SELECT count(number) FROM number_five_thousand WHERE number=5002;
// 0.00404125
结果如下:
2000 el - 索引 0.00099250 未索引 - 0.00226275
5000 el - 索引 0.00095600 未索引 - 0.00404125
10000 el - 索引 0.00156900 未索引 - 0.00761750
这是信息图。 它显示了元素数量如何取决于索引/未索引列的最坏情况查询时间。 索引是红色。 当我测试速度时,我在 mysql 控制台中输入了 2 次相同的查询,因为我发现当您第一次进行查询时,有时查询未索引列甚至比索引列还要快一点。 问题是:为什么这种对 200000 个元素的查询有时比对列号进行索引时对 100000 个元素的相同查询花费的时间更少。 你可以看到还有其他对我来说不可预测的结果。 我问这个,因为当列号没有被索引时,结果是可以预测的:200000 el 时间总是大于 100000。请告诉我在尝试对 UNIQUE 索引列进行研究时我做错了什么。
在未索引的情况下,它始终是全表扫描,因此时间与行号很好地吻合,如果它被索引,您正在测量索引查找时间,这在您的情况下是恒定的(小数字,小偏差)
这还不是“最坏”的情况。
UNIQUE
密钥随机而不是与 PK 处于锁定步骤。 这样的一个例子是UUID()
。如果两者兼而有之,您最终会看到性能显着下降。
UNIQUE
键对INSERTs
有以下影响:在返回给客户端之前检查唯一性约束。 对于非 UNIQUE 索引,插入索引的 BTree 的工作可以(并且已经)延迟。 (参见“更改缓冲区”)。由于第二列上没有索引,因此要做的工作更少。
WHERE number=2002
--
UNIQUE(number)
-- 深入 BTree。 非常快,非常有效率。INDEX(number)
-- 深入 BTree。 非常快,非常有效率。 但是它稍微慢一些,因为它不能假设只有一个这样的行。 也就是说,在 BTree 中找到正确的位置后,它将向前扫描(非常有效),直到找到 2002 以外的值。number
索引——扫描整个表。 所以成本取决于表的大小,而不是number
的值。 它不知道 2002 是否存在于表中的任何位置,或者存在多少次。 如果你绘制你得到的时间,你会发现它是相当线性的。 我建议您在图表中使用 log-log 'paper'。 无论如何,请注意非索引情况的线性程度。 并且索引的情况基本上是恒定的。 查找 number=200002 与查找 number=2002 一样便宜。 这适用于UNIQUE
和INDEX
。 (实际上,由于 BTree 确实是 O(log n),而不是 O(1),因此行中有非常小的上升。对于 2K 行,BTree 中可能有 2 个级别;对于 200K,则为 3 个级别。)
查询缓存可以在时间上绊倒您(如果它已打开)。 计时时,请执行SELECT SQL_NO_CACHE ...
以避免 QC。 如果 QC 开启并应用,那么相同查询的第二次和后续运行将花费非常接近 0.000 秒。
那些在 0.5 毫秒和 1.2 毫秒之间变化的时间 - 将其归结为月相。 说真的,任何低于 10 毫秒的时间都不应该被信任。 这是因为计算机上可能同时发生的所有其他事情。 您可以通过平均多次运行来稍微调整它——确保避免 (1) 查询缓存和 (2) I/O。
至于 I/O...这又回到了我之前关于当表(和/或索引)大于 RAM 中缓存时可能发生的情况的评论。
从技术上讲,您的标签不正确。 MySQL的索引大多是BTrees(实际上是B+Trees),而不是二叉树。 (当然,有很多相似之处,许多原则是共享的。)
回到你的研究目标。
执行任何SELECT
的主要成本是它接触了多少行。
UNIQUE
索引,它触及 1 行。 所以期待快速和 O(1) (加上噪音)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.