mysql - 强制查询优化器使用主键

标签 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 表声明中,但仍未使用。

我可以做些什么来加速这个查询?谢谢。

最佳答案

您的查询正在从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) 上的 challenges 、latest_followup ) — 复杂的键可能会帮助 MySQL 更快地工作。但问题也可能出在您的查询之外...通常当您EXPLAIN并且在rows列中只看到一个包含大数字的表时,您的查询就很好了优化得很好。 MySQL 仅查看 challenge_properties 中的一行和 challenge_contents 中的一行,并扫描 challenges 中的每一行以查找匹配项。

编辑2:

不幸的是,我不确定还可以做什么来优化这个查询。如果使用的索引(cc.challenge_idcp.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/

相关文章:

MySQL:如何获取总和列的最大值?

php - 错误: Champ 'product_name' inconnu dans field list

mysql - MySQL 中何时使用单引号、双引号和反引号

mysql - MySQL 中的过滤行效率

mysql - SQL AUTO_INCRMENT PRIMARY KEY 仅适用于唯一名称字段

php - 从 services.msc 启动服务时出现 mysql 错误

SQL更新查询在where子句中使用聚合函数和group by?

MySQL 在 LEFT JOIN 之前计算字段值

mysql - MySQL如何合并连接表的行数,包括0?

用于选择修复行数 "families"的 SQL