索引下推(ICP)是MySQL 5.6引入的一种优化技术,它允许在存储引擎层提前过滤数据,减少不必要的数据回表操作。
对于辅助联合索引(name,age,position),传统查询流程(MySQL 5.6之前):
sql
SELECT * FROM employees WHERE name LIKE 'LiLei%' AND age = 22 AND position ='manager'
使用ICP优化后的流程:
MySQL没有对范围查找使用ICP优化可能有以下原因:
LIKE 'KK%'
通常能过滤出较小比例的数据(前缀匹配)>
, <
, BETWEEN
)可能匹配大量数据,ICP效果不明显LIKE 'KK%'
)非常适合ICP使用 EXPLAIN
查看执行计划,关注 Extra
列是否包含 Using index condition
:
EXPLAIN SELECT * FROM employees
WHERE name LIKE 'LiLei%' AND age = 22 AND position = 'manager';
如果输出中包含 Using index condition
,则说明 ICP 已生效。
ICP通过将WHERE条件过滤下推到存储引擎,减少了不必要的回表操作,特别对前缀匹配等条件效果显著。范围查询未使用ICP主要是基于性能优化器的权衡,认为这种情况下ICP的收益可能不明显。
ICP 主要优化以下类型的查询:
LIKE 'xxx%'
)。>
、<
、BETWEEN
) + 等值条件。IN
列表或多列等值匹配。LIKE 'xxx%'
)适用场景:联合索引的第一个字段使用前缀匹配,其他字段用于过滤。
示例:
-- 假设有联合索引 (name, age, position)
SELECT * FROM employees
WHERE name LIKE 'LiLei%' AND age = 22 AND position = 'manager';
ICP 优化:
name LIKE 'LiLei%'
过滤索引,回表后再检查 age
和 position
。name
、age
和 position
,仅回表满足所有条件的记录。>
、<
、BETWEEN
)适用场景:联合索引的第一个字段是范围查询,其他字段用于过滤。
示例:
-- 假设有联合索引 (age, salary, department)
SELECT * FROM employees
WHERE age > 30 AND salary = 5000 AND department = 'IT';
ICP 优化:
age > 30
过滤索引,回表后再检查 salary
和 department
。age
、salary
和 department
,减少回表次数。注意:
虽然范围查询(如 age > 30
)本身可能无法完全利用索引的有序性,但 ICP 仍可对后续等值条件(如 salary = 5000
)进行过滤。
IN
条件适用场景:联合索引的第一个字段是 IN
列表,其他字段用于过滤。
示例:
-- 假设有联合索引 (department, status, hire_date)
SELECT * FROM employees
WHERE department IN ('IT', 'HR') AND status = 'active' AND hire_date > '2020-01-01';
ICP 优化:
department IN ('IT', 'HR')
过滤索引,回表后再检查其他条件。department
、status
和 hire_date
,减少回表。适用场景:联合索引的多个字段均为等值匹配。
示例:
-- 假设有联合索引 (city, country, zip_code)
SELECT * FROM addresses
WHERE city = 'Beijing' AND country = 'China' AND zip_code = '100000';
ICP 优化:
city
和 country
过滤索引(最左前缀),回表后再检查 zip_code
。适用场景:索引列上使用简单函数或表达式,且优化器能下推。
示例:
-- 假设有联合索引 (UPPER(name), age)
SELECT * FROM employees
WHERE UPPER(name) LIKE 'LILEI%' AND age = 22;
ICP 优化:
UPPER(name)
和 age
。SUBSTRING
、DATE_FORMAT
)可能无法下推。IS NULL
或 IS NOT NULL
适用场景:联合索引的字段包含空值检查。
示例:
-- 假设有联合索引 (email, phone, status)
SELECT * FROM users
WHERE email IS NOT NULL AND phone = '123456789' AND status = 'active';
ICP 优化:
email IS NOT NULL
、phone
和 status
,减少回表。适用场景:联合索引的字段混合使用范围和等值条件。
示例:
-- 假设有联合索引 (join_date, salary, department)
SELECT * FROM employees
WHERE join_date BETWEEN '2020-01-01' AND '2023-01-01'
AND salary = 8000
AND department = 'Engineering';
ICP 优化:
join_date
范围、salary
和 department
,减少回表。