在日常开发中,MySQL索引调优是非常重要的一环,一个好的SQL索引和语句带来的提升可不是一点半点,尤其对于访问量巨大的数据库业务来说。
而复合索引是索引中最常见的一种索引方式,但如果用的不对,可能效果会直线下降,本文聊聊使用复合索引的一些tips。
1:什么是复合索引?
复合索引是一种包含多个列的索引。与单列索引不同,它专为处理跨多个列的过滤而设计,举个例子,假设有一个包含 CustomerID、OrderDate 和 OrderStatus 的复合索引。
CREATE INDEX IX_Order_Summary
ON dbo.Orders (CustomerID, OrderDate, OrderStatus);
如果你经常通过这三个列进行查询过滤,那么复合索引将显著加速搜索效率。
但复合索引有一个限制:列的顺序非常重要。要想复合索引生效,WHERE 子句中的列顺序必须与索引中的列顺序从左到右一致。
2:为什么列的顺序重要?
以上面列举的复合索引为说明,数据库可以优化从左到右顺序开始的查询,例如:
• 仅按 CustomerID 过滤
• 按 CustomerID 和 OrderDate 过滤
• 按 CustomerID、OrderDate 和 OrderStatus 过滤
可以忽略右边的列,但不能跳过中间的列。如果尝试仅通过 OrderDate 和 OrderStatus 过滤而不使用 CustomerID,那么这个索引将变得无效,数据库不会使用它。
下面详细描述,包含四个小点。
3:遵循从左到右的顺序
复合索引在查询从左到右顺序完全匹配时效果最佳。如果 WHERE 子句中的第一个条件是索引的左侧列(例如 CustomerID),那么该索引就可以被利用。如果不是,索引可能会被忽略,查询将失去优化优势。
这条语句OK:
SELECT *
FROM dbo.Orders
WHERE CustomerID = 123 AND OrderDate = '2024-10-15' AND OrderStatus = 'Shipped';
4:不要跳过中间的列
跳过列是使用复合索引时最常见的错误之一。例如,如果你仅按 OrderDate 和 OrderStatus 过滤而不使用中间的 CustomerID,数据库无法利用复合索引来优化此查询。一定要从左到右依次包含列。
这条语句不OK:
SELECT *
FROM dbo.Orders
WHERE OrderDate = '2024-10-15' AND OrderStatus = 'Shipped';
5:只使用部分索引也可以
部分索引相当于减少重复构建索引的需要,这条语句OK:
SELECT *
FROM dbo.Orders
WHERE CustomerID = 123;
6:小心使用范围条件
在使用范围条件(例如 <、> 或 LIKE)时,要注意它们会限制索引的使用。例如,如果在 OrderDate 上应用了范围条件,然后再按 OrderStatus 过滤,数据库只能使用到 OrderDate 列,而忽略右边的列。
范围条件会阻止索引在后续列上的优化效果,比如下面的复合索引会失效,只能会使用部分索引。
SELECT *
FROM dbo.Orders
WHERE CustomerID = 123 AND OrderDate > '2024-10-01' AND OrderStatus = 'Shipped';
7:为什么不用多个单列索引替代复合索引?
反向思考非常重要,单列索引(例如仅在 CustomerID、OrderDate 和 OrderStatus 上分别创建单独的索引)有时可以提高查询性能,但在大多数情况下,复合索引更具优势。
查询效率更高:复合索引是针对多列的组合而设计的,数据库可以在一次扫描中使用多个列进行过滤,减少了查询的 I/O 开销。如果仅使用单列索引,数据库必须通过多个单列索引逐一查找并合并结果,开销更大。
节省存储空间:单列索引需要为每个列分别创建一个索引结构,占用额外的存储空间。而复合索引将多列合并在一个索引结构中,节省了存储空间,特别是在大数据量的情况下更明显。
减少索引维护成本:每当表数据发生更新(插入、更新或删除)时,数据库都需要维护相关的索引。多个单列索引意味着多次维护开销,增加了数据库的负担。而复合索引只需维护一个索引结构,降低了数据库的维护成本。
更符合实际业务需求:通常查询条件并不是单一列,而是多列组合的过滤(如根据客户、订单日期和订单状态进行筛选)。复合索引能够更好地适应这种多列过滤的需求,从而提升业务查询的整体效率。
over!




