联系支持

我们通过电子邮件回复,通常两天内。

为防止滥用,Google reCAPTCHA 会检查这次提交,其间会向 Google 传输数据。脚本只在你打开此表单时才加载。

← 全部文章

加索引反而更慢的时候

存放每日数字的那张表只有一个键:计数器和日期合在一起。代码里有五处向它提的是另一个问题 — 不是「这个计数器随时间的变化」,而是「这些日子里的所有计数器」。首页的展示区、排行榜、站点地图、一张 90 天的图表,还有状态数字。日期列上没有索引时,它们每一个都要读完全部 114,113 行。

加上那个索引,展示区快十倍。我们没有加。下面是做出这个决定的测量。

展示区,一天 — 61.5 到 6.1 毫秒 排行榜,30 天 — 88.6 到 89.2 毫秒 站点地图,14 天 — 79.6 到 94.8 毫秒 90 天图表 — 120.0 到 109.2 毫秒 状态数字,365 天 — 204.9 到 225.1 毫秒 上面一条没有索引,下面一条有索引 合计:555 毫秒变成 524 毫秒

一个查询快了很多

展示区要的是今天有过访问的计数器。日期上没有索引时,它把整张表走一遍;有索引时,它查一个日期,读 443 行。61.5 毫秒变成了 6.1 毫秒。这不是细微的结果,如果它是唯一被测量的东西,那个索引现在就在数据库里了。

两个查询变慢了

站点地图要的是十四天,慢了 19 %。状态数字要的是一年,慢了 10 %。两种情况下,查询计划器都从主键换到了新索引,并且选错了。

这是值得弄明白的部分,因为它不是计划器的缺陷。通过二级索引读一个区间,意思是:先在索引里找到匹配的行,再把每一行从表里取出来。对一小片来说这很划算。对十三个月里的十四天来说,仍然是很多行、一行一行地取,而直接把表走一遍 — 按物理顺序读,这正是磁盘和缓存喜欢的方式 — 会赢。计划器不知道这一点。它看到一个区间和一个索引,就用了。

你没法说「这个索引只给展示区用」。索引对每一个碰到该列的查询都是可用的,计划器会在它的估算认为该用的地方用它。加一个索引,是对这张表上所有查询的改动,而不是对你心里想的那一个。

合起来:什么都没有

五个加在一起,555 毫秒变成 524 毫秒。1.1 倍的改善,在一台本来就从缓存里发这些页面的树莓派上,不值得改一次表结构。

90 天图表看起来改善了 9 %。它没有被计入,值得说说为什么。每个查询都测了三轮:没有索引、有索引、然后再一次没有索引。如果第二轮没有索引的结果没有落在第一轮附近,那差别来自机器,而不是这次改动。90 天图表的两轮无索引测量相差 13.8 % — 比想要声称的效果还大。所以那一行什么也没测出来,就按什么也没有来报告。

怎么测的,以及为什么这很重要

不在运行中的表上测。脚本复制一份,在副本上工作,最后把副本删掉。为了看看会发生什么而给生产表加索引,这种事每种意外只能做一次。

这些查询是真的,从代码里取出来的,包括与计数器表的连接。这个测试的早期版本用了一个简化的替身,给出的答案要令人兴奋得多:快二十倍。那个简化的查询没有任何地方在执行。

本来会得到的数字

如果按通常的方式测 — 拿一个感觉慢的查询,改动前后各计一次时 — 答案会是「快十倍,上」。索引会加上,展示区会变快,站点地图和状态页会变慢,而且没有人会把这两件事联系起来,因为没有人在看那两个。

这就是事情的一般形状。对共享基础设施的改动,不能用引发它的那个案例来评估。要问的不是「这对我正在看的东西有帮助吗」,而是「它还碰到了什么,那些东西会怎么样」。

有一个版本可能行得通:一个带上两列的索引,日期在前,这样展示区只靠索引就能回答,不必回到表里去。它也许还不会在宽区间上诱惑计划器。这一点没有测过,所以它不是建议 — 它是下一个要放到副本上去的东西。

广告