我正在阅读MySQL文档,了解如何解释EXPLAIN计划的结果。我在顶部看到以下段落:
EXPLAIN为SELECT中使用的每个表返回一行信息陈述它按MySQL会在处理声明时阅读它们。这意味着MySQL从第一个表中读取一行,然后在第二个表,然后在第三个表,依此类推。当所有表处理,MySQL输出选定的列并回溯浏览表列表,直到找到一个表匹配的行。从该表中读取下一行,然后处理继续下表。如果我正确地解释了这一点,这意味着可以通过乘以";行";每个表的部分,因为如果表1的每一行都可以有表2的一行,等等
举个例子,下面是我试图调试的一个查询:
SELECT DISTINCT DISTINCT roles.id, roles.*
FROM `roles`
INNER JOIN `resources`
ON `resources`.`role_id` = `roles`.`id`
INNER JOIN `resources` `workspace_resources_roles`
ON `workspace_resources_roles`.`role_id` = `roles`.`id`
AND `workspace_resources_roles`.`type`
IN ('WorkspaceResource')
INNER JOIN workspaces
ON resources.subject_id = workspaces.id
AND resources.subject_type = "Workspace"
WHERE `roles`.`account_id` = 6804175
AND `roles`.`deleted_at` IS NULL
AND `resources`.`type` = 'WorkspaceResource'
AND `resources`.`user_id` IS NULL
AND `workspaces`.`archived` = FALSE
AND `workspaces`.`account_id` = 6804175
AND `roles`.`id` = 1205685
ORDER BY roles.name ASC
以下是其解释计划:
id 1
select_type SIMPLE
table roles
partitions NULL
type const
possible_keys PRIMARY,index_roles_on_account_id_and_deleted_at_and_name,index_roles_on_account_id
key PRIMARY
key_len 4
ref const
rows 1
filtered 100.0
Extra Using temporary
id 1
select_type SIMPLE
table resources
partitions NULL
type index_merge
possible_keys index_resources_on_user_id,index_resources_on_role_id,index_resources_on_type,index_resources_on_subject_id_and_subject_type,index_resources_on_subject_id
key index_resources_on_role_id,index_resources_on_user_id
key_len 5,5
ref NULL
rows 4075
filtered 2.5
Extra Using intersect(index_resources_on_role_id,index_resources_on_user_id); Using where; Distinct
id 1
select_type SIMPLE
table workspaces
partitions NULL
type eq_ref
possible_keys PRIMARY,index_workspaces_on_account_id
key PRIMARY
key_len 4
ref mavenlink_production.resources.subject_id
rows 1
filtered 5.0
Extra Using where; Distinct
id 1
select_type SIMPLE
table workspace_resources_roles
partitions NULL
type ref
possible_keys index_resources_on_role_id,index_resources_on_type
key index_resources_on_role_id
key_len 5
ref const
rows 32620
filtered 50.0
Extra Using where; Distinct
表1有1行,表2有4075行,表3有1行和表4有32620行。在最坏的情况下,这是否意味着1*4075*1*32620=132936500行的总结果集?如果是这样的话,这就解释了为什么这个查询在我们的生产环境中需要173秒。
您在解释EXPLAIN方面走在了正确的轨道上。您有一个没有子查询的简单查询,并且将每个联接表的rows
相乘。根据优化器计算的估计,这大致是要检查的行数。
请注意,优化器的估计值相当粗略。不要认为它们是准确的。
如果您有子查询,或者使用LIMIT
,那么这种解释所检查行的方法会变得更加复杂。
如果您想要一个真实的测量,而不是EXPLAIN的估计,那么执行查询(不使用EXPLAIN(,并运行SHOW SESSION STATUS LIKE 'Handler%';
。它将向您显示存储引擎运行的操作数量。像Handler_read_next或Handler_read_rnd这样的操作对应于检查的行。在两次测试之间运行FLUSH STATUS
,将会话状态值清零。