知识卡片
多列索引列序:选择性优先不如避免随机I/O和排序重要
内容
B-Tree多列索引的行是按最左列排序、同最左列值下再按下一列排序,逐层嵌套,
这决定了它只能高效支持”从最左列开始连续匹配”的查询模式,也决定了列的先后
顺序不是随意的,会实质性影响查询效率。一条常被提及的经验法则是”把选择性
最高的列放在最前面”,理由是这样能让索引在查找阶段就过滤掉尽可能多的行。
以payment表为例,判断该把staff_id还是customer_id放前面,既可以用
具体查询值做值级对比(SELECT SUM(staff_id=2), SUM(customer_id=584) ...
看哪个条件命中的行更少),也可以用全局选择性对比
(COUNT(DISTINCT col)/COUNT(*)看哪一列整体区分度更高),两种方法在这个
例子里都指向应该把customer_id放在staff_id前面。但书中明确把这条
“选择性优先”法则的地位放低:它只是个经验法则,重要性通常不如另外两个
考量——避免随机I/O和避免排序。换句话说,列序选择的真正目标是让索引尽量
支撑住查询实际的访问模式(等值匹配范围更广、少触发排序、少产生随机磁盘
访问),选择性只是这个目标下的一个辅助信号,不能脱离具体查询模式单独
套用。这条法则本身还有个更深的陷阱:它建立在”平均选择性能代表真实查询会
遇到的选择性”这个假设上,而
[[前缀索引长度要按最坏情况选择性而非平均值来定]]和实际的”特殊用户”案例
都说明,一旦某个具体值的基数远高于平均水平,按平均选择性排出的列序在
这个特殊值上可能完全不管用。
参考来源
- 位置:《高性能MySQL:第3版》第5章"创建高性能的索引"5.3.4节"选择合适
的索引列顺序"(源文件:_epub-src/OEBPS/Text/part0012.xhtml)
- 结论依据:原文通过payment表的staff_id/customer_id对比示例给出选择性
优先的判断方法,同时明确指出"这个经验法则值得考虑,但是这不如避免
随机I/O和排序那么重要",说明选择性只是列序决策中的次要考量。
- 原始内容:这个经验法则值得考虑,但是这不如避免随机I/O和排序那么重要,
在下一节会有一个例子。一般来说,在不损害查询性能的情况下,将选择性
最高的列放在索引最前列通常是一个好主意。