如何优化这个查询?

ash*_*osh 1 mysql performance index-tuning query-performance

询问:

Select * 
from `t_event` 
where `create_user_id`=7 
and (`event_create_date`)=('2012-12-18 00:00:00')
and `event_type_cd`=11
and `domain_id` =602
and `job_id` =1
limit 1
Run Code Online (Sandbox Code Playgroud)

表结构:

mysql> show create table t_event\G
*************************** 1. row ***************************
       Table: t_event
Create Table: CREATE TABLE `t_event` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `create_user_id` int(11) DEFAULT NULL,
  `event_create_date` date DEFAULT NULL,
  `event_type_cd` int(11) NOT NULL,
  `event_desc` varchar(512) NOT NULL,
  `IsGlobalEvent` int(2) DEFAULT NULL,
  `event_start_date` datetime NOT NULL,
  `event_end_date` datetime NOT NULL,
  `job_id` int(11) DEFAULT NULL,
  `domain_id` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `event_user_FK` (`create_user_id`),
  KEY `domain_id_event_type_cd` (`domain_id`,`event_type_cd`)
) ENGINE=InnoDB AUTO_INCREMENT=8095673 DEFAULT CHARSET=utf8
1 row in set (0.03 sec)
Run Code Online (Sandbox Code Playgroud)

解释:

+----+-------------+---------+-------------+---------------------------------------+---------------------------------------+---------+------+-------+---------------------------------------------------------------------+
| id | select_type | table   | type        | possible_keys                         | key                                   | key_len | ref  | rows  | Extra                                                               |
+----+-------------+---------+-------------+---------------------------------------+---------------------------------------+---------+------+-------+---------------------------------------------------------------------+
|  1 | SIMPLE      | t_event | index_merge | event_user_FK,domain_id_event_type_cd | domain_id_event_type_cd,event_user_FK | 8,5     | NULL | 14669 | Using intersect(domain_id_event_type_cd,event_user_FK); Using where |
+----+-------------+---------+-------------+---------------------------------------+---------------------------------------+---------+------+-------+---------------------------------------------------------------------+
Run Code Online (Sandbox Code Playgroud)

如何优化此查询?它有索引,但执行时间太长。

ype*_*eᵀᴹ 8

您的查询在 5 个不同的列中有 5 个相等条件:

select * 
from t_event 
where create_user_id=7 
  and event_create_date = '2012-12-18 00:00:00'  
  and event_type_cd = 11 
  and domain_id = 602 
  and job_id =1 

limit 1 ;                  -- why is this for?
Run Code Online (Sandbox Code Playgroud)

现在你有 2 个索引(domain_id_event_type_cdevent_user_FK),它们仅涵盖查询的 5 个列/条件中的 3 个。

所以优化器选择的计划是一个index_merge操作,例如它使用两个索引分别找到符合 2 和 1 条件的行,然后将它们相交 ( Using intersect) 以找到公共行,然后必须对表进行额外的搜索( Using where) 对于索引未涵盖的其余 2 个条件。


您可以在所有这些列上添加复合索引。顺序对于此查询根本不重要,它对于您可能有的其他查询以及是否可以用于它们很重要:

ALTER TABLE t_event 
    ADD INDEX i5
        (domain_id, event_type_cd, create_user_id, event_create_date, job_id) ;
Run Code Online (Sandbox Code Playgroud)

然后Explain将仅显示Using index并且仅使用上述索引。