2

我有一个表,我最近将几个列的类型从 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 |
+----+-------------+----------------------------+------+----------------------------------------------+----------------------------------------------+---------+-------+--------+-------------+
4

2 回答 2

0

根据我的经验,当您有或在枚举字段上时,MySQL不喜欢使用索引。尝试翻转查询以检查显式值。where not in<>

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')));
于 2013-11-05T18:54:58.710 回答
0

由于您在选择中使用

most_recent_status is null OR (most_recent_status not in ('SENT', 'ERROR'))

规划师不会使用您的密钥。因为没有办法在这样的where子句中使用 key。

所以它唯一可以使用的是

 transmitter_type = 'FAX_1' AND transmission_id = ''

但在您的情况下,规划师认为您在索引中有很多与这些值相关的行,因此使用索引没有优势。

您可以强制使用索引,但认为它不会有帮助。可能您需要考虑将查询重写为更具体的方式(例如添加“order by most_recent_attempt_date limit 10”并首先使用 most_recent_attempt_date 创建键)

此外,如果不在 most_recent_status 中使用空值(在枚举中输入“未定义”)并使用使用状态值的查询而不是查询用户设置(in/not in),您也可以获得更高的性能。

于 2013-11-05T18:14:10.797 回答