我正在运行一个跨越 3 个表的查询,其中没有一个表的行数超过 55K。此查询运行时间超过 20 秒,这似乎过多:
SELECT
`cp`.`author`,
`cc`.`contents`
FROM
`challenge_properties` as `cp`,
`challenges` as `c`,
`challenge_contents` as `cc`
WHERE
`cp`.`followup_id` = `c`.`latest_followup` AND
`cp`.`status` = 'new' AND
`c`.`id` = `cp`.`challenge_id` AND
`c`.`id` = `cc`.`challenge_id`
这是该查询的EXPLAIN
结果:
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: c
type: ALL
possible_keys: PRIMARY,latest_followup_index
key: NULL
key_len: NULL
ref: NULL
rows: 13817
Extra:
*************************** 2. row ***************************
id: 1
select_type: SIMPLE
table: cc
type: ref
possible_keys: challenge_id
key: challenge_id
key_len: 5
ref: cts.c.id
rows: 1
Extra: Using where
*************************** 3. row ***************************
id: 1
select_type: SIMPLE
table: cp
type: ref
possible_keys: challenge_id,followup_id
key: followup_id
key_len: 5
ref: cts.c.latest_followup
rows: 1
Extra: Using where
如您所见,第一个表 challenges
有一个主键,但未使用。我尝试将 FORCE KEY(PRIMARY)
子句添加到 challenges
表声明中,但仍未使用。
我可以做些什么来加速这个查询?谢谢。
最佳答案
您的查询正在从challenges
表中选择所有记录 - 因此无需对该表中的记录使用任何索引。基本上,MySQL 会选择challenges
中的每条记录,然后在其他两个表中查找匹配的记录。
你不能把挑战
表一起省略吗?您没有从该表中选择数据,并且该表限制所选数据的唯一时间是当您的其他表具有无效的 challenge_id
时,外键可以处理该问题...
SELECT
`cp`.`author`,
`cc`.`contents`
FROM
`challenge_properties` as `cp`,
`challenge_contents` as `cc`
WHERE
`cp`.`status` = 'new' AND
`cp`.`challenge_id` = `cc`.`challenge_id`
编辑:您说您无法从查询中删除challenges
表...我会尝试在JOIN
中指定您的JOIN
条件code> 子句而不是 WHERE
:
SELECT
`cp`.`author`,
`cc`.`contents`
FROM `challenge_properties` as `cp`
JOIN `challenges` as `c`
ON `cp`.`challenge_id` = `c`.`id`
AND `cp`.`followup_id` = `c`.`latest_followup`
JOIN `challenge_contents` as `cc`
ON `cc`.`challenge_id` = `c`.`id`
WHERE `cp`.`status` = 'new'
查询优化器可能已经为您执行此操作,但尝试一下并没有什么坏处,而且我认为使用此语法可以更轻松地了解连接是如何发生的。
您还可以尝试将另一个索引添加到 (challenge_id, followup_id )
上的 challenge_properties
,并将另一个索引添加到 (challenge_id) 上的
— 复杂的键可能会帮助 MySQL 更快地工作。但问题也可能出在您的查询之外...通常当您challenges
、latest_followup )EXPLAIN
并且在rows
列中只看到一个包含大数字的表时,您的查询就很好了优化得很好。 MySQL 仅查看 challenge_properties
中的一行和 challenge_contents
中的一行,并扫描 challenges
中的每一行以查找匹配项。
编辑2:
不幸的是,我不确定还可以做什么来优化这个查询。如果使用的索引(cc.challenge_id
和 cp.followup_id
)是 UNIQUE NOT NULL
索引,您可以获得稍微更高的性能,并且您应该得到在 (cp.challenge_id, cp.followup_id)
上使用 cp
的复杂索引可以获得更好的性能。这会将这些 type: ref
转换为 type: eq_ref
,这会稍微好一些。但仅此而已...您对其他查询没有任何问题吗?理论上你的查询应该返回 13817 行...数据量可能是问题吗?如果您只选择 COUNT(*)
而不是返回所有行,速度是否会显着提高?
关于mysql - 强制查询优化器使用主键,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9522156/