mysql索引列与非索引列的研究

gz5pxeao  于 2021-06-18  发布在  Mysql
关注(0)|答案(2)|浏览(742)

我分别生成了包含2000、5000、10000、50000、10000、20000、50000、100000、200000个元素的mysql innodb表(借助php循环和insert query)。每个表有两列:id(主键int autoincrement)、number(int unique key)。然后我做了同样的操作,但这次我生成了类似的表,其中numbercolumn没有索引,我以这样的方式生成表:column 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.0026275
5000 el-索引0.00095600未索引-0.00404125
10000 el-索引0.00156900未索引-0.00761750
20000 el-索引0.00155850未索引-0.01452820
50000 el-索引0.00051100未索引-0.04127450
100000 el索引0.00121750未索引-0.07120075
200000 el索引0.00095025未索引-0.11406950
这是这方面的信息图表。它显示了元素的数量如何依赖于索引列/未索引列的最坏查询时间。它是红色的。当我测试速度时,我在mysql控制台中输入了两次相同的查询,因为我发现当您第一次进行查询时,有时对未索引列的查询甚至比对已索引列的查询快一点。问题是:为什么这种类型的对200000个元素的查询有时比对列编号进行索引时对100000个元素的查询花费更少的时间。你可以看到还有其他不可预知的结果。我问这个问题,因为当列号没有索引时,结果是可以预测的:200000 el时间总是大于100000。请告诉我,当我试图研究唯一索引列时,我做错了什么。

lh80um4z

lh80um4z1#

这不是“最坏”的情况。
使 UNIQUE 随机键,而不是与pk同步锁定。这方面的一个例子是 UUID() .
生成足够的行,使表和索引无法放入缓冲池。
如果你同时使用这两种方法,你最终会看到性能明显下降。 UNIQUE 关键点对 INSERTs :在返回到客户端之前检查唯一性约束。对于非唯一索引,要插入到索引的btree中的工作可能会(并且会)延迟(cf“更改缓冲区”)。如果第二列没有索引,那么要做的工作就更少了。 WHERE number=2002 --
UNIQUE(number) --向下钻取btree。速度很快,效率很高。
INDEX(number) --向下钻取btree。速度很快,效率很高。但是,它稍微慢了一点,因为它不能假设只有一行。也就是说,在btree中找到正确的位置后,它将向前扫描(非常有效),直到找到2002以外的值。
没有索引 number --扫描整个表格。因此,成本取决于表的大小,而不是表的值 number . 它不知道2002年是否存在于表中的任何地方,也不知道有多少次。如果你画出你得到的时间,你会发现它是相当线性的。
我建议你用日志纸做图表。不管怎样,请注意非索引大小写是多么线性。索引的情况基本上是不变的。查找number=200002和查找number=2002一样便宜。这适用于 UNIQUE 以及 INDEX . (实际上,这条线有一个很小的上升,因为btree实际上是o(logn),而不是o(1)。对于2k行,btree中可能有2个级别;对于200k,3个级别。)
查询缓存可能会在计时上绊倒您(如果它已打开)。在计时的时候,做什么 SELECT SQL_NO_CACHE ... 避免质量控制。如果qc已打开并应用,则相同查询的第二次和后续运行将花费非常接近0.000秒的时间。
那些在0.5到1.2毫秒之间变化的时间——把它归为月球的相位。说真的,任何低于10毫秒的时间都是不可信的。这是因为计算机上可能同时发生的所有其他事情。您可以通过平均多次运行来调整它——确保避免(1)查询缓存和(2)i/o。
至于i/o。。。这又回到了我之前的评论,当表(和/或索引)大于可以缓存在ram中的值时会发生什么。
当小于ram时,第一次运行可能会从磁盘中获取内容。第二次和随后的运行可能会更快和一致。
当内存大于ram时,所有的运行可能都需要命中磁盘。因此,一切都可能是缓慢的,也许比你发现的变化更脆弱。
从技术上讲,你的标签是不正确的。mysql的大多数索引都是b树(实际上是b+树),而不是二叉树(当然,有很多相似之处,而且许多原则是共享的。)
回到你的研究目标。
假设有“背景噪音”干扰了你的数字。
使你的测试不琐碎(如非索引的情况),以便它压倒噪音,或
重复计时以掩盖问题。一定要忽略第一次跑步。
执行任何操作的主要成本 SELECT 它接触了多少行。
用你的 UNIQUE 索引,它是接触1行。所以期待快速和o(1)(加上噪音)。
如果没有索引,对于一个n行的表,它将接触n行。所以期待o(n)。

eufgjt7s

eufgjt7s2#

在没有索引的情况下,它始终是一个完整的表扫描,因此时间与行号很好地协调,如果它被索引,则您正在测量索引查找时间,在您的情况下它是恒定的(小数字,小偏差)

相关问题