我有一个表,我最近将几个列的类型从varchar更改为enum(见下文)。我的应用程序在这两列上对此表进行查询,并且在进行类型更改后,我发现此查询的性能严重下降(我已经包含了下面的查询以及解释计划结果)。到目前为止,我一直无法在这里找到罪魁祸首,希望有人遇到这个问题并提出建议。
desc order_transmission_history;
+--------------------------+--------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------------------+--------------+------+-----+---------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| transmission_id | varchar(255) | YES | | NULL | |
| transmitter_type | varchar(10) | YES | MUL | NULL | |
| initial_attempt_date | timestamp | NO | MUL | CURRENT_TIMESTAMP | |
| most_recent_attempt_date | timestamp | NO | | 0000-00-00 00:00:00 | |
| most_recent_status | varchar(16) | YES | | NULL | |
+--------------------------+--------------+------+-----+---------------------+----------------+
索引为:KEY transmission_history_transmitter_status_date
(transmitter_type
,most_recent_status
,initial_attempt_date
)
explain SELECT * FROM order_transmission_history where transmitter_type = 'FAX_1' AND transmission_id = '' AND (most_recent_status is null or (most_recent_status not in ('SENT', 'ERROR')));
+----+-------------+----------------------+-------+-------------------------------------------------------------------------------------------+----------------------------------------------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------------------+-------+-------------------------------------------------------------------------------------------+----------------------------------------------+---------+------+------+-------------+
| 1 | SIMPLE | transmission_history | range | transmission_history_transmitter_status_date | transmission_history_transmitter_status_date | 32 | NULL | 350 | Using where |
+----+-------------+----------------------+-------+-------------------------------------------------------------------------------------------+----------------------------------------------+---------+------+------+-------------+
现在,使用更改的数据类型:
+--------------------------------------+----------------------------------------------------------------------------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------------------------------+----------------------------------------------------------------------------------+------+-----+-------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| transmission_id | varchar(255) | YES | | NULL | |
| initial_attempt_date | timestamp | NO | MUL | CURRENT_TIMESTAMP | |
| most_recent_attempt_date | timestamp | YES | | NULL | |
| transmitter_type | enum('FAX_1','FAX_2','FAX_3','EMAIL') | YES | MUL | NULL | |
| most_recent_status | enum('NONE','PENDING','TRANSIENT_ERROR','ERROR','SENDING','SENT','SYSTEM_ERROR') | YES | | NULL | |
+--------------------------------------+----------------------------------------------------------------------------------+------+-----+-------------------+----------------+
explain SELECT * FROM order_transmission_history where transmitter_type = 'FAX_1' AND transmission_id = '' AND (most_recent_status is null or (most_recent_status not in ('SENT', 'ERROR')));
+----+-------------+----------------------------+------+----------------------------------------------+----------------------------------------------+---------+-------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------------------------+------+----------------------------------------------+----------------------------------------------+---------+-------+--------+-------------+
| 1 | SIMPLE | order_transmission_history | ref | transmission_history_transmitter_status_date | transmission_history_transmitter_status_date | 2 | const | 394992 | Using where |
+----+-------------+----------------------------+------+----------------------------------------------+----------------------------------------------+---------+-------+--------+-------------+
答案 0 :(得分:0)
由于您在选择中使用
most_recent_status is null OR (most_recent_status not in ('SENT', 'ERROR'))
计划者不会使用您的密钥。因为没有办法使用带有where
子句的密钥。
所以唯一可以使用的是
transmitter_type = 'FAX_1' AND transmission_id = ''
但是在你的情况下,计划者认为你在索引中有很多带有这些值的行,所以没有优势使用索引。
您可以强制使用索引,但不要认为它会有所帮助。您可能需要考虑将查询重写为更具体的方法(例如,添加"按order_recent_attempt_date限制10"并首先使用most_recent_attempt_date创建密钥)
如果不在most_recent_status中使用空值(在枚举中放置'未定义'),则可以获得更多性能,并使用使用状态值的查询而不是用户设置的查询(在/不在其中)。 / p>
答案 1 :(得分:0)
根据我的经验,当你在枚举字段上有where not in
或<>
时,MySQL 不喜欢使用索引。请尝试翻转查询以检查显式值。
SELECT * FROM order_transmission_history
where transmitter_type = 'FAX_1'
AND transmission_id = ''
AND (most_recent_status is null or
(most_recent_status in
('NONE','PENDING','TRANSIENT_ERROR','SENDING','SYSTEM_ERROR')));