强制查询优化器使用主键

时间:2012-03-01 18:51:20

标签: mysql

我正在运行一个跨越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表声明中,但它仍未使用。

我该怎么做才能加快查询速度?感谢。

1 个答案:

答案 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:

不幸的是,我不确定还可以采取哪些措施来优化此查询。如果使用的索引(challengescc.challenge_id)是cp.followup_id索引,您可以获得更高的性能,并且UNIQUE NOT NULL cp上的复杂索引应该可以获得更好的性能1}}。这会将(cp.challenge_id, cp.followup_id)转换为type: ref,这稍微好一些。但那是关于它的......你没有遇到任何其他疑问的问题吗?您的查询理论上应该返回13817行...数据量可能是问题吗?如果您只选择type: eq_ref而不是返回所有行,它会显着加快速度吗?