ICP 减少的是 不必要 的回表,而不是 所有 回表
- 必须回表的情况:
- 如果查询需要返回索引中 未包含 的列,那么 无论是否开启 ICP,都必须进行回表操作。 这是因为索引本身只存储了部分列的数据,要获取其他列的数据,只能回到主表中查询。
- 例如,如果索引只包含
first_name
和last_name
列,而查询需要返回hire_date
列,那么就必须进行回表。
- 可以避免回表的情况:
- ICP 优化的正是这种情况。 当
WHERE
子句中包含可以使用索引中的列进行评估的条件时,ICP 可以在索引层先进行过滤,减少那些不满足条件的数据的回表操作。
- ICP 优化的正是这种情况。 当
再次分析示例:
假设有 employees
表,包含 emp_no
, first_name
, last_name
, hire_date
等列。
CREATE TABLE employees (emp_no INT PRIMARY KEY,first_name VARCHAR(50),last_name VARCHAR(50),hire_date DATE
);-- 创建联合索引
CREATE INDEX idx_first_name_last_name ON employees (first_name, last_name);
执行以下查询:
SELECT * FROM employees WHERE first_name = 'John' AND last_name LIKE '%son%';
关键点:即使开启了 ICP,仍然需要回表!
-
原因: 查询
SELECT *
需要返回employees
表的所有列,包括hire_date
列,而idx_first_name_last_name
索引 不包含hire_date
列。 因此,无论是否开启 ICP,都必须进行回表操作。 -
ICP 的作用: ICP 在这个例子中的作用是,减少了需要回表的记录数量。
- 没有 ICP: 存储引擎找到所有
first_name = 'John'
的记录,然后 全部 回表,Server 层再过滤last_name LIKE '%son%'
。 - 有 ICP: 存储引擎找到
first_name = 'John'
的记录,同时 使用last_name LIKE '%son%'
在索引层进行过滤,只有满足last_name LIKE '%son%'
的记录才会被回表。
- 没有 ICP: 存储引擎找到所有
总结:
- ICP 并没有消除回表操作,而是减少了 不必要 的回表操作。
- 如果查询需要返回索引中未包含的列,那么无论是否开启 ICP,都必须进行回表。
- ICP 的价值在于,当
WHERE
子句中包含可以使用索引中的列进行评估的条件时,可以在索引层先进行过滤,减少那些不满足条件的数据的回表操作。