0Pricing
SQL Interview Prep · 课时

复合索引的列顺序

掌握最左前缀规则,并为工作负载选择合适的列顺序。

复合索引的列顺序 是 CoddyKit 上的免费 SQL Interview Prep 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 SQL Interview Prep 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 SQL Interview Prep 课程共包含 4 节课。

复合索引问题

当您已经能够解释单列索引后,面试官会提高难度:“您会同时按客户标识和订单日期进行查询。您会如何为其建立索引?”预期答案是复合(多列)索引,并说明列顺序的依据。

本课将讲解最左前缀规则,这是几乎所有复合索引面试问题背后的核心概念。

什么是复合索引

复合索引会将多个列作为一个有序元组进行索引。条目先按第一列排序,再在第一列值相同的情况下按第二列排序,以此类推,就像电话簿先按姓氏排序,再按名字排序一样。

顺序极其重要,因为排序优先级取决于您声明列时所采用的顺序。

CREATE INDEX idx_orders_cust_date
  ON orders (customer_id, order_date);

最左前缀规则

核心规则是:对于 (A, B, C) 上的复合索引,可以用于筛选这些列的最左前缀的查询:

  • 仅 A,可以
  • A, B,可以
  • A, B, C,可以
  • 仅 B,NO
  • B, C,NO

可以把它想成电话簿:您可以找到所有姓“史密斯”的人,但无法高效地找到所有名字是“约翰”而不论姓氏的人,因为电话簿并不是按照这种方式排序的。

示例:命中前缀

对于 (customer_id, order_date) 上的索引,以下查询可以使用它,因为它们都以 customer_id 开头:

第一个查询只使用最左列。第二个查询同时使用两列:先按 customer_id 缩小范围,再在该客户按日期排序的条目中进行查找。

-- Uses the index (leading column)
SELECT * FROM orders WHERE customer_id = 42;

-- Uses the index fully (both columns, in order)
SELECT * FROM orders
WHERE customer_id = 42
  AND order_date >= '2026-01-01';

示例:未命中前缀

这个查询只按第二列进行筛选,因此通常无法使用 (customer_id, order_date) 上的索引来驱动查找,因为这些条目并没有按 order_date 进行全局排序。

如果单独按 order_date 筛选是常见模式,您就需要创建一个以 order_date 开头的独立索引。

-- Does NOT use idx_orders_cust_date efficiently
SELECT * FROM orders
WHERE order_date >= '2026-01-01';

-- Fix: an index that leads with order_date
CREATE INDEX idx_orders_date ON orders (order_date);

先等值,后范围

一个面向资深开发者的进一步要点是:将用于等值匹配(=)的列放在用于范围查询(<、>、BETWEEN)的列之前。索引一旦遇到范围列,就无法再利用后面的列来缩小查找范围。

对于 status = 'paid' AND created_at > ? 这样的查询,正确的顺序是 (status, created_at),而不是反过来。

-- Query: WHERE status = 'paid' AND created_at > '2026-01-01'
-- Good: equality column first
CREATE INDEX idx_orders_status_created
  ON orders (status, created_at);

选择最左列

您应该如何选择放在第一位的列?面试官希望听到基于工作负载的回答:

  • 将出现在最多查询中的列放在最前面,尤其是作为等值筛选条件时。
  • 优先选择具有高选择性(不同值很多)的列,这样第一步就能排除最多的行。
  • 考虑ORDER BY 的需求:匹配索引顺序可以避免排序。

最左列应该是在真实查询组合中承担最繁重筛选工作的列。

复合索引有助于排序

复合索引也可以服务于最左前缀上的 ORDER BY。由于条目先按 customer_id、再按 order_date 排序,因此查询某个客户按日期排序的订单时,几乎不需要额外成本,也无需单独排序。

-- No sort step: the index already supplies this order
SELECT * FROM orders
WHERE customer_id = 42
ORDER BY order_date;

不要堆叠冗余索引

候选人经常会创建过多索引。如果您已经有了 (customer_id, order_date),那么单独创建一个 (customer_id) 索引通常是冗余的,因为复合索引已经覆盖了以第一列开头的查询。

每增加一个索引都会占用存储空间并拖慢写入,因此目标应该是使用最少的一组索引覆盖您的查询模式,而不是为每一列创建一个索引。

使用 EXPLAIN 证明

和往常一样,请确认规划器的选择。创建复合索引后,运行 EXPLAIN,检查它是否显示为索引扫描,以及规划器估算的行数是多少。

如果前缀不匹配的查询退回到顺序扫描,这就是列顺序不适合工作负载的证据,也正是您在面试中应该解释的内容。

EXPLAIN
SELECT * FROM orders
WHERE customer_id = 42
  AND order_date >= '2026-01-01';

面试时如何表述

一句简洁的总结:

“复合索引会从左到右按照列进行排序,因此可以服务于这些列的任意最左前缀,但不能服务于只有后续列的子集。我会将筛选最多、选择性高的列放在最前面,将等值谓词放在范围谓词之前,并尽可能匹配 ORDER BY,最后使用 EXPLAIN 进行验证。”

快速检查

应用最左前缀规则。

回顾:复合索引顺序

要点总结:

  • 复合索引按从左到右排序;它只能服务于其列的最左前缀。
  • 将查询最频繁且选择性最高的列放在最前面。
  • 将等值列置于范围列之前。
  • 匹配的前缀还可以在无需排序的情况下满足 ORDER BY。
  • 避免创建已被复合索引覆盖的冗余单列索引,并使用 EXPLAIN 进行验证。

下一节:能够完全消除堆读取的覆盖索引。

常见问题解答

「复合索引的列顺序」课时是免费的吗?

是的 — 「复合索引的列顺序」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 SQL Interview Prep 课程的其余内容,请升级到 CoddyKit PRO。 SQL Interview Prep 课程共包含 4 节课。

「复合索引的列顺序」这节课中我会学到什么?

掌握最左前缀规则,并为工作负载选择合适的列顺序。 你通过在浏览器中直接运行的动手代码来练习 SQL Interview Prep,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 SQL Interview Prep 需要有经验吗?

无需任何先前经验。CoddyKit 上的 SQL Interview Prep 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「复合索引的列顺序」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 SQL Interview Prep 课中编写并运行代码吗?

能。每节 SQL Interview Prep 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. B 树索引及其作用
  2. 复合索引的列顺序
  3. 覆盖索引与仅索引扫描
  4. 索引何时有害:写入与选择性
← 返回 SQL Interview Prep