问题描述
我有一张表:student_homework,它的综合索引之一是uk_sid_lsnid_version(student_id,lesson_id,curriculum_version,type)
:
student_homework 0 uk_sid_lsnid_version 1 student_id A 100 BTREE
student_homework 0 uk_sid_lsnid_version 2 lesson_id A 100 BTREE
student_homework 0 uk_sid_lsnid_version 3 curriculum_version A 100 BTREE
student_homework 0 uk_sid_lsnid_version 4 type A 100 BTREE
现在我有一个sql:
select * from student_homework where student_id=100 and type=1
和explain
的结果是:
1 SIMPLE student_homework ref uk_sid_lsnid_version,idx_student_id_update_time uk_sid_lsnid_version 4 const 20 10.0 Using index condition
执行计划为 uk_sid_lsnid_version 。
对我来说,问题是查询条件type
在这里如何工作?数据库引擎是否扫描所有(缩小的)记录?以我的理解,树的层次结构是:
student_id
/ \
lesson_id lesson_id
/ \
curriculum_version curriculum_version
/ \
type type
对于查询条件(student_id,类型),student_id
与树索引的根匹配。但是,type
与索引lesson_id
不匹配,数据库引擎会将type
应用于已被student_id
过滤的所有记录。
- 我的理解正确吗?如果带有
student_id
的子集记录很大,则查询成本仍然很高。 - 查询条件 student_id = 100和类型= 0 和 type = 0和Student_id = 100 之间没有区别
- 要充分利用复合索引,如果添加新的复合索引(student_id,type)会更好吗?
解决方法
是的,您的理解是正确的,mysql将仅使用uk_sid_lsnid_version
索引来匹配student_id
,而对type
的过滤将在与之匹配的精简行集合上进行。 student_id
。
提示位于解释结果的extra
列中:Using index condition
使用索引条件(JSON属性:using_index_condition)
通过访问索引元组并首先对其进行测试以确定是否读取完整的表行来读取表。这样,除非有必要,否则索引信息将用于延迟(“下推”)读取整个表行。请参见第8.2.1.6节“索引条件下推优化”。
Section 8.2.1.6,“Index Condition Pushdown Optimization将这种技术的步骤描述为:
- 获取下一行的索引元组(而不是整个表行)。
- 测试适用于此表的WHERE条件部分,仅可使用索引列进行检查。如果条件不是 如果满意,请转到下一行的索引元组。
- 如果满足条件,则使用索引元组来定位并读取整个表行。
- 测试适用于此表的WHERE条件的其余部分。根据测试结果接受或拒绝该行。
在student_id上添加另一个复合索引是否更好,类型是我们无法客观回答的问题,您需要对其进行测试。
如果使用当前索引进行查询的速度很好,那么您可能不需要新索引。您还需要权衡使用该索引的其他查询的数量-仅为一个查询创建索引没有多大意义。您还需要权衡type
字段的选择性。值列表有限的类型字段通常不够选择性。由于student_id,类型index不是覆盖索引,因此mysql可能决定使用索引条件下推式,而mysql仍然必须获得完整的行。