3
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. 评论表的 userEmail。
  4. 评论表上的复合索引(typeId,type)。
  5. 用户表的电子邮件(唯一)
  6. 自动化的评论表。
  7. 评论表的添加时间。

行数:
1. 流 - 150k
2. 评论 - 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 |
4

1 回答 1

1

You have the required indexes to perform the joins efficiently. However, it looks like MySQL is joining the tables in a less efficient manner. The EXPLAIN output shows that it is doing a full index scan of the flows table then joining the comments table.

It will probably be more efficient to read the comments table first before joining. That is, in the order you have specified in your query so that the comment set is restricted by the predicates you have supplied (probably what you intended).

Running OPTIMISE TABLE or ANALYZE TABLE can improve the decision that the query optimiser makes. Particularly on tables that have had extensive changes.

If the query optimiser still gets it wrong you can force tables to be read in the order you specify in the query by beginning your statement with SELECT STRAIGHT_JOIN or by changing the INNER JOIN to STRAIGHT_JOIN.

于 2013-07-25T22:34:24.173 回答