知识卡片

多列索引列序:选择性优先不如避免随机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和排序那么重要, 在下一节会有一个例子。一般来说,在不损害查询性能的情况下,将选择性 最高的列放在索引最前列通常是一个好主意。