我用2000、5000、10000、50000、10000、20000、50000、100000、200000元素生成了单独的MySQL Innodb表(借助php循环和插入查询)。 每个表都有两列:id(主键INT自动递增),数字(INT UNIQUE KEY)。然后我做了同样的事情,但是这次我生成了类似的表,其中 number 列没有INDEX 。我以这种方式生成表:列 number 等于索引值+ 2:第一个元素== 3,第1000个元素为1002,依此类推。我想测试这样的查询,因为它将在我的应用程序中使用:
SELECT count(number) FROM number_two_hundred_I WHERE number=200002;
为这些表生成数据后,我想测试最坏情况查询的时间。我使用了SHOW PROFILES。我假设最坏情况的查询将对应于列值为 number 的元素,值为1002,2002,依此类推,因此这是我测试过的所有查询和时间(由显示个人资料):
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
这里是infographic。它显示了元素数如何取决于索引/未索引列的最坏情况查询时间。索引为红色。 测试速度时,我在mysql控制台中两次键入了相同的查询,因为我发现第一次进行查询时,有时对未索引列的查询甚至会更快一些,比索引的要多。问题是:为什么对索引编号的列进行这种类型的查询200000元素有时花费的时间少于同一查询100000元素的时间。您可以看到还有其他无法预测的结果。我之所以这样问,是因为当不对列号进行索引时,结果是可以预测的:200000 el time总是大于100000。请告诉我在尝试对UNIQUE索引列进行研究时我做错了。
答案 0 :(得分:0)
在未建立索引的情况下,它始终是全表扫描,因此时间与行号很好地匹配,如果已建立索引,则您正在测量索引查找时间,该时间在您的情况下是恒定的(数字较小,偏差很小)>
答案 1 :(得分:0)
这不是最糟糕的情况。
UNIQUE
键是随机的,而不是与PK保持同步。例如UUID()
。如果同时使用这两者,则最终会发现性能显着下降。
UNIQUE
键对INSERTs
具有以下影响:在返回客户之前检查唯一性约束。对于非UNIQUE索引,插入索引BTree的工作可能会(并且被)延迟。 (参见“更改缓冲区”。第二列没有索引,要做的工作更少。
WHERE number=2002
-
UNIQUE(number)
-深入BTree。非常快,非常有效。INDEX(number)
-深入BTree。非常快,非常有效率。但是,由于不能假设只有这样的一行,所以速度稍慢。也就是说,在BTree中找到正确的位置后,它将向前扫描(非常有效),直到找到2002以外的值。number
上没有索引-扫描整个表。因此,成本取决于表的大小,而不取决于number
的值。它不知道2002年表中的任何位置或存在次数。如果绘制时间,将发现它是线性的。我建议您对图形使用对数日志“纸”。无论如何,请注意非索引大小写的线性度。并且索引大小写基本上是恒定的。查找号码= 200002与查找号码= 2002一样便宜。这适用于UNIQUE
和INDEX
。 (实际上,由于BTree确实是O(log n),而不是O(1),所以行中的上升很小。对于2K行,BTree中可能有2个级别;对于200K行,则是3个级别。) / p>
查询缓存可以使您按时跳闸(如果已打开)。计时时,请执行SELECT SQL_NO_CACHE ...
以避免质量控制。如果启用了质量控制并应用了质量控制,则相同查询的秒和随后的运行将非常接近0.000秒。
那些时间在0.5毫秒至1.2毫秒之间变化-将其计时到月相。严重的是,任何低于10ms的时序都不应被信任。这是由于 可能同时在计算机上发生的所有其他情况。您可以通过平均多次运行来对它进行调整-确保避免(1)查询缓存和(2)I / O。
关于I / O ...这可以回溯到我之前的评论,即当表(和/或索引)大于可缓存在RAM中时可能发生的情况。
从技术上讲,您的标签不正确。 MySQL的大多数索引都是BTrees(实际上是B + Trees),而不是Binary Trees。 (当然,有很多相似之处,并且许多原则是共享的。)
回到您的研究目标。
执行任何SELECT
的 main 成本是它接触的行数。
UNIQUE
索引,它正在触及1行。因此,请期待快速和O(1)(加上噪声)。