MySql:使用index_merge优化子查询

时间:2017-12-22 15:21:29

标签: mysql indexing

我想列出所有用户以及简报订阅的状态。如果有人在订阅时事通讯时不需要成为用户,我就会这样做:

SELECT user.id, user.email,
(SELECT newsletter.status FROM newsletter 
      WHERE newsletter.email=user.email OR newsletter.user = user.id) AS status
FROM user
WHERE...

索引是user.id,user.email,newsletter.email,newsletter.user。

OR使查询变得异常缓慢。我在这里Union as sub query MySQL发现你可以进行“索引合并”,这将加速查询。但我不确定如何强制MySQL在我的情况下进行索引合并。有什么想法吗?

已添加:第二行说明不使用密钥。

DROP TABLE if exists user;
DROP TABLE if exists newsletter;

create table user (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,
`email` varchar(255) DEFAULT NULL, INDEX email(email)
) ENGINE=InnoDB;

create table newsletter (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,
`status` enum('subscribed','unsubscribed') DEFAULT NULL,
`email` varchar(255) DEFAULT NULL, INDEX email(email),
`user` int(10) unsigned DEFAULT NULL, INDEX user(user)
) ENGINE=InnoDB;

EXPLAIN SELECT user.id, user.email,
(SELECT newsletter.status FROM newsletter 
      WHERE newsletter.email=user.email OR newsletter.user = user.id) AS status
FROM user;

+----+--------------------+------------+------------+-------+---------------+-------+---------+------+------+----------+------------------------------------------------+
| id | select_type        | table      | partitions | type  | possible_keys | key   | key_len | ref  | rows | filtered | Extra                                          |
+----+--------------------+------------+------------+-------+---------------+-------+---------+------+------+----------+------------------------------------------------+
|  1 | PRIMARY            | user       | NULL       | index | NULL          | email | 768     | NULL |    1 |   100.00 | Using index                                    |
|  2 | DEPENDENT SUBQUERY | newsletter | NULL       | ALL   | email,user    | NULL  | NULL    | NULL |    1 |   100.00 | Range checked for each record (index map: 0x6) |
+----+--------------------+------------+------------+-------+---------------+-------+---------+------+------+----------+------------------------------------------------+

EXPLAIN SELECT user.id, user.email, newsletter.status
FROM user
LEFT JOIN newsletter ON (newsletter.email=user.email OR newsletter.user = user.id);

+----+-------------+------------+------------+-------+---------------+-------+---------+------+------+----------+------------------------------------------------+
| id | select_type | table      | partitions | type  | possible_keys | key   | key_len | ref  | rows | filtered | Extra                                          |
+----+-------------+------------+------------+-------+---------------+-------+---------+------+------+----------+------------------------------------------------+
|  1 | SIMPLE      | user       | NULL       | index | NULL          | email | 768     | NULL |    1 |   100.00 | Using index                                    |
|  1 | SIMPLE      | newsletter | NULL       | ALL   | email,user    | NULL  | NULL    | NULL |    1 |   100.00 | Range checked for each record (index map: 0x6) |
+----+-------------+------------+------------+-------+---------------+-------+---------+------+------+----------+------------------------------------------------+

1 个答案:

答案 0 :(得分:1)

除非你有switched off index_merge,否则MySQL会认为它会有用。但是我发现它的启动频率低于预期,即使它确实如此,也不是很有用 - 查询仍然比以传统方式使用索引慢得多。

这些类型的查询的典型解决方案是执行两个更简单查询的UNION。

explain select u.id, u.email, n.status
 from user u left join newsletter n on u.email=n.email
 union
 select u.id, u.email, n.status
 from user u left join newsletter n on u.id=n.user;

+----+--------------+------------+-------+---------------+-------+---------+--------------+------+-----------------+
| id | select_type  | table      | type  | possible_keys | key   | key_len | ref          | rows | Extra           |
+----+--------------+------------+-------+---------------+-------+---------+--------------+------+-----------------+
|  1 | PRIMARY      | u          | index | NULL          | email | 403     | NULL         |    1 | Using index     |
|  1 | PRIMARY      | n          | ref   | email         | email | 403     | test.u.email |    1 | NULL            |
|  2 | UNION        | u          | index | NULL          | email | 403     | NULL         |    1 | Using index     |
|  2 | UNION        | n          | ref   | user          | user  | 5       | test.u.id    |    1 | NULL            |
| NULL | UNION RESULT | <union1,2> | ALL   | NULL          | NULL  | NULL    | NULL         | NULL | Using temporary |
+----+--------------+------------+-------+---------------+-------+---------+--------------+------+-----------------+

您最好修复数据,这样您只需加入用户ID,而不是电子邮件。