我正在运行此查询
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)
我很擅长为这么大的结果集优化查询。我可以看到位置表存在问题,但我不确定要改变什么才能有所作为。非常感谢任何帮助。
答案 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
无论如何,当你不使用这些表时,是没有必要的。