MySql-如何使用索引优化查询?
我们正在尝试从数据库中获取跟踪者的最新10个通知。我们做了一些连接来确保为跟随者获得正确的通知集。如果他们跟随的人(他们的领导者)添加了一个新帖子,那么追随者应该只获得在他们开始跟随领导者之后添加的帖子的通知(没有意义将他们领导者的旧帖子显示为新通知)。另一个连接是确保我们在时间获得通知的MySql-如何使用索引优化查询?,mysql,sql,select,left-join,innodb,Mysql,Sql,Select,Left Join,Innodb,我们正在尝试从数据库中获取跟踪者的最新10个通知。我们做了一些连接来确保为跟随者获得正确的通知集。如果他们跟随的人(他们的领导者)添加了一个新帖子,那么追随者应该只获得在他们开始跟随领导者之后添加的帖子的通知(没有意义将他们领导者的旧帖子显示为新通知)。另一个连接是确保我们在时间获得通知的read\u,以便跟随者知道它是否已经被读取。这是查询,但它需要9秒,速度太慢了。理想情况下,只需几毫秒,特别是索引: 查询: SELECT nf.id, nf.uuid, nf.leader_id, nf.d
read\u,以便跟随者知道它是否已经被读取。这是查询,但它需要9秒,速度太慢了。理想情况下,只需几毫秒,特别是索引:
查询:
SELECT nf.id, nf.uuid, nf.leader_id, nf.data, nf.created_at, nfr.read_at
FROM notification_followers nf
LEFT JOIN user_follows uf ON uf.leader_id = nf.leader_id AND uf.follower_id = 14 AND uf.follow_status = 'follow'
LEFT JOIN notification_followers_read nfr ON nf.id = nfr.notification_followers_id AND nfr.follower_id = 14
WHERE (nf.created_at > uf.created_at)
ORDER BY nf.id DESC
LIMIT 10
ALTER TABLE `notification_followers` ADD INDEX `nf_lid_ca_id_idx` (`leader_id`,`created_at`,`id`);
ALTER TABLE `user_follows` ADD KEY`uf_fid_lid_fs_ca_idx` (`follower_id`,`leader_id`,`follow_status`,`created_at`)
ALTER TABLE `notification_followers_read` ADD INDEX `nfr_fid_nfid_ra_idx` (`follower_id`,`notification_followers_id`,`read_at`);
索引:
SELECT nf.id, nf.uuid, nf.leader_id, nf.data, nf.created_at, nfr.read_at
FROM notification_followers nf
LEFT JOIN user_follows uf ON uf.leader_id = nf.leader_id AND uf.follower_id = 14 AND uf.follow_status = 'follow'
LEFT JOIN notification_followers_read nfr ON nf.id = nfr.notification_followers_id AND nfr.follower_id = 14
WHERE (nf.created_at > uf.created_at)
ORDER BY nf.id DESC
LIMIT 10
ALTER TABLE `notification_followers` ADD INDEX `nf_lid_ca_id_idx` (`leader_id`,`created_at`,`id`);
ALTER TABLE `user_follows` ADD KEY`uf_fid_lid_fs_ca_idx` (`follower_id`,`leader_id`,`follow_status`,`created_at`)
ALTER TABLE `notification_followers_read` ADD INDEX `nfr_fid_nfid_ra_idx` (`follower_id`,`notification_followers_id`,`read_at`);
解释:
SELECT nf.id, nf.uuid, nf.leader_id, nf.data, nf.created_at, nfr.read_at
FROM notification_followers nf
LEFT JOIN user_follows uf ON uf.leader_id = nf.leader_id AND uf.follower_id = 14 AND uf.follow_status = 'follow'
LEFT JOIN notification_followers_read nfr ON nf.id = nfr.notification_followers_id AND nfr.follower_id = 14
WHERE (nf.created_at > uf.created_at)
ORDER BY nf.id DESC
LIMIT 10
ALTER TABLE `notification_followers` ADD INDEX `nf_lid_ca_id_idx` (`leader_id`,`created_at`,`id`);
ALTER TABLE `user_follows` ADD KEY`uf_fid_lid_fs_ca_idx` (`follower_id`,`leader_id`,`follow_status`,`created_at`)
ALTER TABLE `notification_followers_read` ADD INDEX `nfr_fid_nfid_ra_idx` (`follower_id`,`notification_followers_id`,`read_at`);
正确的结果(需要约9秒):
SELECT nf.id, nf.uuid, nf.leader_id, nf.data, nf.created_at, nfr.read_at
FROM notification_followers nf
LEFT JOIN user_follows uf ON uf.leader_id = nf.leader_id AND uf.follower_id = 14 AND uf.follow_status = 'follow'
LEFT JOIN notification_followers_read nfr ON nf.id = nfr.notification_followers_id AND nfr.follower_id = 14
WHERE (nf.created_at > uf.created_at)
ORDER BY nf.id DESC
LIMIT 10
ALTER TABLE `notification_followers` ADD INDEX `nf_lid_ca_id_idx` (`leader_id`,`created_at`,`id`);
ALTER TABLE `user_follows` ADD KEY`uf_fid_lid_fs_ca_idx` (`follower_id`,`leader_id`,`follow_status`,`created_at`)
ALTER TABLE `notification_followers_read` ADD INDEX `nfr_fid_nfid_ra_idx` (`follower_id`,`notification_followers_id`,`read_at`);
SQL转储:
SELECT nf.id, nf.uuid, nf.leader_id, nf.data, nf.created_at, nfr.read_at
FROM notification_followers nf
LEFT JOIN user_follows uf ON uf.leader_id = nf.leader_id AND uf.follower_id = 14 AND uf.follow_status = 'follow'
LEFT JOIN notification_followers_read nfr ON nf.id = nfr.notification_followers_id AND nfr.follower_id = 14
WHERE (nf.created_at > uf.created_at)
ORDER BY nf.id DESC
LIMIT 10
ALTER TABLE `notification_followers` ADD INDEX `nf_lid_ca_id_idx` (`leader_id`,`created_at`,`id`);
ALTER TABLE `user_follows` ADD KEY`uf_fid_lid_fs_ca_idx` (`follower_id`,`leader_id`,`follow_status`,`created_at`)
ALTER TABLE `notification_followers_read` ADD INDEX `nfr_fid_nfid_ra_idx` (`follower_id`,`notification_followers_id`,`read_at`);
只需在本地创建speed\u test
数据库并导入文件,就可以看到所有表数据(~100K行)的慢查询问题
我们如何优化上述内容以在几毫秒内获得正确的结果?对于此查询:
SELECT nf.id, nf.uuid, nf.leader_id, nf.data, nf.created_at, nfr.read_at
FROM notification_followers nf JOIN
user_follows uf
ON uf.leader_id = nf.leader_id AND uf.follower_id = 14 AND
uf.follow_status = 'follow' LEFT JOIN
notification_followers_read nfr
ON nf.id = nfr.notification_followers_id AND nfr.follower_id = 14
WHERE nf.created_at > uf.created_at
ORDER BY nf.id DESC
LIMIT 10;
我会推荐关于用户跟随者(领导者id、跟随者id、跟随者状态、创建时间)的索引和通知跟随者读取(通知跟随者id、跟随者id、读取时间)
。索引中列的顺序很重要
注意,我将第一个JOIN
更改为一个内部联接,因为WHERE
子句将其转换为一个联接
嗯,让我们尝试重写查询:
SELECT nf.id, nf.uuid, nf.leader_id, nf.data, nf.created_at,
(SELECT nfr.read_at
FROM notification_followers_read nfr
WHERE nf.id = nfr.notification_followers_id AND nfr.follower_id = 14
) nfr
FROM (SELECT nf.*
FROM notification_followers nf
WHERE EXISTS (SELECT 1
FROM user_follows uf
WHERE uf.leader_id = nf.leader_id AND uf.follower_id = 14 AND
uf.follow_status = 'follow' AND nf.created_at > uf.created_at
)
ORDER BY nf.id DESC
LIMIT 10
) nf;
为此,您需要确保在notification\u followers(id)
上也有索引
根据您的数据,使用这种方法,内部子查询可能会更快:
FROM (SELECT nf.*
FROM user_follows uf JOIN
notification_followers nf
ON uf.leader_id = nf.leader_id AND nf.created_at > uf.created_at
WHERE uf.follower_id = 14 AND uf.follow_status = 'follow'
ORDER BY nf.id DESC
LIMIT 10
) nf
为此,索引为user\u follows(follower\u id,follow\u status,leader\u id,created\u at)
和notification\u followers(leader\u id,created\u at,id)
。这可能会更快 你应该试试这个
SELECT nf.id, nf.uuid, nf.leader_id, nf.data, nf.created_at, nfr.read_at
FROM notification_followers nf
JOIN user_follows uf ON uf.leader_id = nf.leader_id and nf.created_at > uf.created_at AND uf.follow_status = 'follow' AND uf.follower_id = 14
LEFT JOIN notification_followers_read nfr ON nf.id = nfr.notification_followers_id AND nfr.follower_id = 14
ORDER BY nf.id DESC
LIMIT 10;
在上创建索引
ALTER TABLE `notification_followers` ADD INDEX `nf_lid_ca_id_idx`(`leader_id`,`created_at`,`id`);
ALTER TABLE `user_follows` ADD KEY`uf_fid_lid_fs_ca_idx`(`leader_id`,`created_at`,`follow_status`,`follower_id`)
ALTER TABLE `notification_followers_read` ADD INDEX `nfr_fid_nfid_ra_idx`(`notification_followers_id`,`follower_id`,`read_at`);
六羟甲基三聚氰胺六甲醚。。。实现了查询/索引,但需要约7秒。顺便说一句,您的查询缺少我添加到您的查询中的限制10
,但仍然需要很长时间才能获得结果。因此,使用原始索引建议重写的查询在follower_id14
(需要几毫秒)上运行得非常快,但当我将其更改为follower_id1
,没有返回结果,这是正确的,但需要~4s才能返回结果。有没有办法让它像14
那样更快地卷土重来?顺便说一句,我试着用相应的索引替换内部子查询,但是对于14
我的上一条评论有任何反馈吗?@Wonka。不是真的。不清楚为什么id的选择很重要,除非“1”有很多、更多的行与之关联。事实上,1没有任何行与之关联,这就是为什么奇怪的是,它需要超过几毫秒才能返回它没有结果。不管怎样,您的查询确实帮助提高了速度,因此感谢您对查询和索引进行了重新构造:)这是一个内部联接,对吗?不确定,但是使用当前的左联接返回正确的结果
通知被读取后,通知\u followers\u id是否会存在于通知\u followers\u read表中?还是始终可用?读取后。您的查询不会在问题中返回正确的结果。我已对您的问题发表了评论,并根据该假设进行了工作,现在,我已经根据您的评论进行了更正。因此,id14
返回结果需要约4秒,而不是几毫秒。另一方面,id1
返回正确的结果(没有项目)需要几毫秒。因此,这与戈登·林诺夫(Gordon Linoff)的上述回答(见我的评论)正好相反。我希望两者都能得到几毫秒,不管是使用id14
还是1
。