我正在运行一个跨越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
表声明中,但它仍未使用。
我该怎么做才能加快查询速度?感谢。
答案 0 :(得分:2)
您的查询正在从challenges
表中选择所有记录 - 因此无需对该表中的记录使用任何索引。基本上MySQL正在选择challenges
中的每条记录,然后在其他两个表中查找匹配的记录。
难道你不能一起遗漏challenges
表吗?您没有从该表中选择数据,并且该表限制所选数据的唯一时间是,如果您的其他表具有无效的challenge_id
s,外键可以处理...
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
条件而不是{{1} }}:
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_properties
添加另一个索引,在( challenge_id, followup_id )
上向challenges
添加另一个索引 - 复杂的密钥可能会帮助MySQL更快地完成工作。但问题也可能超出您的查询...通常当您( challenge_id, latest_followup )
并且只在EXPLAIN
列中看到一个包含大数字的表时,您的查询就会得到很好的优化。 MySQL只查看rows
中的一行和challenge_properties
中的一行,并扫描challenge_contents
中的每一行以查找匹配项。
编辑2:
不幸的是,我不确定还可以采取哪些措施来优化此查询。如果使用的索引(challenges
和cc.challenge_id
)是cp.followup_id
索引,您可以获得更高的性能,并且UNIQUE NOT NULL
cp
上的复杂索引应该可以获得更好的性能1}}。这会将(cp.challenge_id, cp.followup_id)
转换为type: ref
,这稍微好一些。但那是关于它的......你没有遇到任何其他疑问的问题吗?您的查询理论上应该返回13817行...数据量可能是问题吗?如果您只选择type: eq_ref
而不是返回所有行,它会显着加快速度吗?