【问题标题】:Mysql Slow Query - Even with all the indicesMysql 慢查询 - 即使有所有索引
【发布时间】:2013-07-25 08:23:11
【问题描述】:
mysql> explain
    select c.userEmail,f.customerId 
    from comments c 
      inner join flows f 
        on (f.id = c.typeId) 
      inner join users u 
        on (u.email = c.userEmail) 
    where c.addTime >= 1372617000 
      and c.addTime <= 1374776940 
      and c.type = 'flow' 
      and c.automated = 0;
+----+-------------+-------+--------+----------------------------------------+------------+---------+---------------------+--------+-------------+
| id | select_type | table | type   | possible_keys                          | key        | key_len | ref                 | rows   | Extra       |
+----+-------------+-------+--------+----------------------------------------+------------+---------+---------------------+--------+-------------+
|  1 | SIMPLE      | f     | index  | PRIMARY                                | customerId | 4       | NULL                | 144443 | Using index |
|  1 | SIMPLE      | c     | ref    | userEmail_idx,addTime,automated,typeId | typeId     | 198     | f.id,const  |      1 | Using where |
|  1 | SIMPLE      | u     | eq_ref | email                                  | email      | 386     | c.userEmail |      1 | Using index |
+----+-------------+-------+--------+----------------------------------------+------------+---------+---------------------+--------+-------------+

如何使上述查询更快 - 它不断出现在慢查询日志中。
存在的索引:

  1. id 是流表的自动递增主键。
  2. 流表的customerId。
  3. cmets 表的 userEmail。
  4. cmets 表上的复合索引 (typeId,type)。
  5. 用户表的电子邮件(唯一)
  6. cmets 表的自动化。
  7. cmets 表的添加时间。

行数:
1. 流量 - 150k
2. cmets - 500k(其中一半自动化 = 1,其他自动化 = 0)(除 500 之外的所有行的类型值也是“流”)
3. 用户 - 50

表架构:

 users | CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `email` varchar(128) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `email` (`email`)
) ENGINE=InnoDB AUTO_INCREMENT=56 DEFAULT CHARSET=utf8 

 comments | CREATE TABLE `comments` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `userEmail` varchar(128) DEFAULT NULL,
  `content` mediumtext NOT NULL,
  `addTime` int(11) NOT NULL,
  `typeId` int(11) NOT NULL,
  `automated` tinyint(4) NOT NULL,
  `type` varchar(64) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `userEmail_idx` (`userEmail`),
  KEY `addTime` (`addTime`),
  KEY `automated` (`automated`),
  KEY `typeId` (`typeId`,`type`)
) ENGINE=InnoDB AUTO_INCREMENT=572410 DEFAULT CHARSET=utf8 |


 flows | CREATE TABLE `flows` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `type` varchar(32) NOT NULL,
  `status` varchar(128) NOT NULL,
  `customerId` int(11) NOT NULL,
  `createTime` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `flowType_idx` (`type`),
  KEY `customerId` (`customerId`),
  KEY `status` (`status`),
  KEY `createTime` (`createTime`),
) ENGINE=InnoDB AUTO_INCREMENT=134127 DEFAULT CHARSET=utf8 |

【问题讨论】:

  • 尝试在(automated, type, addTime)上添加索引
  • 忘了说,addTime 上已经有索引了。
  • 刚刚在 cmets 上运行了优化表,解释输出现在显示的行数要少得多。我会看看它是否还能加快应用程序上下文中的查询速度。
  • 显示您的表架构。
  • 这个查询目前需要多长时间?您在寻找哪种减少方式?

标签: mysql query-optimization


【解决方案1】:

您拥有有效执行连接所需的索引。但是,看起来 MySQL 以一种效率较低的方式连接表。 EXPLAIN 输出显示它正在对 flows 表进行全索引扫描,然后加入 comments 表。

在加入之前先读取comments 表可能会更有效。也就是说,按照您在查询中指定的顺序,以便注释集受到您提供的谓词的限制(可能是您想要的)。

运行OPTIMISE TABLEANALYZE TABLE 可以改进查询优化器做出的决策。特别是在发生了广泛变化的表上。

如果查询优化器仍然出错,您可以通过以SELECT STRAIGHT_JOIN 开头的语句或将INNER JOIN 更改为STRAIGHT_JOIN 来强制按照您在查询中指定的顺序读取表。

【讨论】:

  • 感谢您指出 Straight_join。虽然我在某处读到这不是一个理想的解决方案 - 但它有助于优化另一个查询。
猜你喜欢
  • 2015-05-19
  • 1970-01-01
  • 2021-09-17
  • 2013-04-30
  • 1970-01-01
  • 1970-01-01
  • 2012-06-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多