处理数百万条记录时查询速度非常慢。需要帮助来优化

时间:2016-03-21 08:45:05

标签: mysql

我正在运行此查询

mysql> explain SELECT
    recipients.id
FROM
    recipients
JOIN recipient_contact_details ON recipient_contact_details.recipient_id = recipients.id
JOIN recipient_contact_preferences ON recipient_contact_preferences.recipient_id = recipients.id
LEFT JOIN recipient_has_recipient_tags ON recipient_has_recipient_tags.recipient_id = recipients.id
LEFT JOIN recipient_tags ON recipient_tags.id = recipient_has_recipient_tags.recipient_tag_id
LEFT JOIN recipient_tag_groups ON recipient_tag_groups.id = recipient_tags.recipient_tag_group_id
INNER JOIN location ON location.id = recipients.location_id
WHERE
    1 = 1
AND FLOOR(
    DATEDIFF(NOW(), recipients.dob) / 365
) > 15
AND recipients.`join_date` < '2016-02-27 16:35:46'
AND recipients.`last_attendance` > '2016-02-18 16:35:46'
AND location.deleted_at IS NULL
AND recipient_contact_details.type = 1
AND recipient_contact_details.
VALUE
    != '';

(我为长度道歉!) - 从2.7 + m记录的收件人表中返回大约900 + k行。它确实如此,但运行大约需要25-30秒。

运行explain后,我可以看到:

+----+-------------+-------------------------------+--------+------------------------------------------------------------------+------------------------------------------------------------------+---------+---------------------------------------------------------+-------+-----------------------------------------------------------------+
| id | select_type | table                         | type   | possible_keys                                                    | key                                                              | key_len | ref                                                     | rows  | Extra                                                           |
+----+-------------+-------------------------------+--------+------------------------------------------------------------------+------------------------------------------------------------------+---------+---------------------------------------------------------+-------+-----------------------------------------------------------------+
|  1 | SIMPLE      | location                      | ALL    | PRIMARY,location_id_index                                        | NULL                                                             | NULL    | NULL                                                    |   156 | Using where                                                     |
|  1 | SIMPLE      | recipients                    | ref    | PRIMARY,recipients_location_id_index                             | recipients_location_id_index                                     | 5       | homestead.location.id                                   | 17918 | Using index condition; Using where                              |
|  1 | SIMPLE      | recipient_contact_preferences | ref    | recipient_contact_preferences_recipient_id_index                 | recipient_contact_preferences_recipient_id_index                 | 4       | homestead.recipients.id                                 |     1 | Using where; Using index                                        |
|  1 | SIMPLE      | recipient_has_recipient_tags  | ref    | recipient_has_recipient_tags_recipient_id_recipient_tag_id_index | recipient_has_recipient_tags_recipient_id_recipient_tag_id_index | 4       | homestead.recipients.id                                 |     2 | Using where; Using index                                        |
|  1 | SIMPLE      | recipient_contact_details     | ref    | recipient_contact_details_recipient_id_index                     | recipient_contact_details_recipient_id_index                     | 4       | homestead.recipients.id                                 |     2 | Using index condition; Using where                              |
|  1 | SIMPLE      | recipient_tags                | eq_ref | PRIMARY                                                          | PRIMARY                                                          | 4       | homestead.recipient_has_recipient_tags.recipient_tag_id |     1 | Using where                                                     |
|  1 | SIMPLE      | recipient_tag_groups          | index  | PRIMARY                                                          | PRIMARY                                                          | 4       | NULL                                                    |     2 | Using where; Using index; Using join buffer (Block Nested Loop) |
+----+-------------+-------------------------------+--------+------------------------------------------------------------------+------------------------------------------------------------------+---------+---------------------------------------------------------+-------+-----------------------------------------------------------------+
7 rows in set (0.00 sec)

正如您所看到的,我已经添加了(我认为相关索引到各个表中)。位置表是

    mysql> desc location;
+------------------+------------------+------+-----+---------------------+----------------+
| Field            | Type             | Null | Key | Default             | Extra          |
+------------------+------------------+------+-----+---------------------+----------------+
| id               | int(10) unsigned | NO   | PRI | NULL                | auto_increment |
| created_at       | timestamp        | NO   |     | 0000-00-00 00:00:00 |                |
| updated_at       | timestamp        | NO   |     | 0000-00-00 00:00:00 |                |
| name             | varchar(255)     | NO   |     | NULL                |                |
| deleted_at       | timestamp        | YES  |     | NULL                |                |
| org_website      | varchar(255)     | NO   |     | NULL                |                |
| from_name        | varchar(255)     | NO   |     | NULL                |                |
| reply_to_address | varchar(255)     | NO   |     | NULL                |                |
| logo_path        | varchar(255)     | NO   |     | NULL                |                |
| colour           | varchar(255)     | NO   |     | NULL                |                |
| street_address   | varchar(255)     | NO   |     | NULL                |                |
| city             | varchar(255)     | NO   |     | NULL                |                |
| region           | varchar(255)     | NO   |     | NULL                |                |
| postcode         | varchar(255)     | NO   |     | NULL                |                |
| country          | varchar(255)     | NO   |     | NULL                |                |
| privacy_url      | varchar(255)     | NO   |     | NULL                |                |
| remote_id        | bigint(20)       | NO   | MUL | 0                   |                |
+------------------+------------------+------+-----+---------------------+----------------+
17 rows in set (0.00 sec)

我很擅长为这么大的结果集优化查询。我可以看到位置表存在问题,但我不确定要改变什么才能有所作为。非常感谢任何帮助。

1 个答案:

答案 0 :(得分:1)

请在recipients.dob上创建索引

CREATE INDEX idx_recipients_dob ON recepients(dob);

并重写:

AND FLOOR(
    DATEDIFF(NOW(), recipients.dob) / 365
) > 15

到此:

AND recipients.dob < NOW() - INTERVAL 15 YEAR

我想,这可能已经解决了你所有的问题 重写是必要的,因为如果对索引列进行任何计算,MySQL就无法使用索引。此外,它更容易阅读,更准确(你忘了闰年)。

这些加入

LEFT JOIN recipient_has_recipient_tags ON recipient_has_recipient_tags.recipient_id = recipients.id
LEFT JOIN recipient_tags ON recipient_tags.id = recipient_has_recipient_tags.recipient_tag_id
LEFT JOIN recipient_tag_groups ON recipient_tag_groups.id = recipient_tags.recipient_tag_group_id
无论如何,当你不使用这些表时,

是没有必要的。