请注意,我已经在dba.stackexchange.com上提出了这个问题,但我想我也会在这里发布:
在MySQL中,我有两个基本表 - 帖子和关注者:
CREATE TABLE Posts (
id int(11) NOT NULL AUTO_INCREMENT,
posted int(11) NOT NULL,
body varchar(512) NOT NULL,
authorId int(11) NOT NULL,
PRIMARY KEY (id),
KEY posted (posted),
KEY authorId (authorId,posted)
) ENGINE=InnoDB;
CREATE TABLE Followers (
userId int(11) NOT NULL,
followerId int(11) NOT NULL,
PRIMARY KEY (userId,followerId),
KEY followerId (followerId)
) ENGINE=InnoDB;
我有以下查询,似乎已经足够优化了:
SELECT p.*
FROM Posts p
WHERE p.authorId IN (SELECT f.userId
FROM Followers f
WHERE f.followerId = 9
ORDER BY authorId)
ORDER BY posted
LIMIT 0, 20
EXPLAIN
输出:
+------+--------------------+-------+-----------------+--------------------+---------+---------+------------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+--------------------+-------+-----------------+--------------------+---------+---------+------------+------+--------------------------+
| 1 | PRIMARY | p | index | NULL | posted | 4 | NULL | 20 | Using where |
| 2 | DEPENDENT SUBQUERY | f | unique_subquery | PRIMARY,followerId | PRIMARY | 8 | func,const | 1 | Using index; Using where |
+------+--------------------+-------+-----------------+--------------------+---------+---------+------------+------+--------------------------+
当followerId
是有效的id(意思是,它实际存在于两个表中)时,查询执行几乎是立即执行的。但是,当表中不存在id时,查询仅在7秒延迟后返回结果(空集)。
为什么会这样?有没有办法在没有匹配的情况下加速查询(无需提前检查)?
答案 0 :(得分:0)
有没有办法加快这个查询...... ???
是。你应该做两件事。
首先,您应该使用EXISTS而不是IN(交叉引用SQL Server IN vs. EXISTS Performance)。它可以加速匹配的情况,随着数据集的增长,它会派上用场(它现在可能足够快,但这并不意味着你不应该这样做。遵循最佳实践,在这种情况下,EXISTS是比IN)更好的实践
其次,您应该稍微修改第二个表上的键。您在(userId,followerId)上使用复合键开始了一个良好的开端,但在优化此特定查询方面,您需要记住最左边的前缀" MySQL索引规则,例如
如果表具有多列索引,则优化程序可以使用索引的任何最左前缀来查找行。 http://dev.mysql.com/doc/refman/5.6/en/multiple-column-indexes.html
来自EXPLAIN的查询执行计划告诉您的是,SQL认为将关注者加入帖子(使用帖子上的主键)更有意义,并过滤掉该索引的给定关注者的结果。可以把它想象为"向我展示所有可能的匹配,然后将其减少到匹配followerId = {}"
的那些匹配如果使用复合键(followerId,userId)替换followerId键,则应该能够快速放大到与给定followerID关联的用户ID,并对其进行存在性检查。
我希望我知道如何更好地解释这个...这是一个难以理解的概念,直到你有一个"啊哈!"时刻和点击。但是如果你查看索引上最左边的前缀规则,并且还将followerId上的键更改为(followerId,userId)上的键,我认为它会加快它的速度。如果您使用EXISTS而不是IN,那么即使您的数据集增长,也可以帮助您保持这种速度。
答案 1 :(得分:0)
试试这个:
SELECT p.*
FROM Posts p
inner join Followers f On f.userId = p.authorId
WHERE f.followerId = 9
ORDER BY posted
LIMIT 0, 20