我正在尝试优化一个sql查询,因为它很慢,而且当查询结果很高时会变得很慢。
SELECT *
FROM comments
WHERE
DATE(created_on) > DATE_SUB(CURDATE(), INTERVAL 1 DAY)
AND comments.group_id = " . $group_id . "
AND comments.user_id != " . $user_id . "
AND NOT EXISTS (
SELECT *
FROM reads
WHERE
comments.post_id = reads.notification_id
AND comments.group_id = reads.group_id
AND reads.user_id = " . $user_id . "
AND comments.nature1 = reads.notification_type
AND comments.created_on < reads.read_date
)
LIMIT 8
有索引相关的字段和表是相当大的。
4条答案
按热度按时间z3yyvxxp1#
作为启动器,此条件:
应重写为:
这在功能上是等价的,不在被筛选的列上使用日期函数会使数据库有机会使用索引。
然后,考虑以下指标:
这是两个多列索引(称为复合索引),而不是每列上的单独索引。你会注意到它们与
where
查询和子查询的 predicate 。索引中列的顺序很重要(尤其是在comments
):首先需要具有相等 predicate 的列,然后是具有不等 predicate 的列。最后:你真的需要吗
select *
? 最好将列表缩小到实际需要的列;如果只有几个,您可能需要尝试将它们添加到上的索引中comments
.旁注:
limit
没有order by
通常没有用。这将为您提供一组任意的匹配行,并且在同一数据集上连续执行同一查询的结果可能不一致考虑使用准备好的语句,而不是在查询字符串中串联变量;这使得mysql能够识别查询,并重用已经准备好的执行计划(这是一个很小的收获,但总是很好的),而且,更重要的是,它可以防止sql注入。
o2g1uqev2#
对于您的查询,您需要索引:
comments(group_id, created_on, user_id)
reads(post_id, group_id, notification_type, user_id, created_on)
.这是你的两个索引吗?
wsewodh23#
微小的潜在改进,替换条款
AND comments.group_id = reads.group_id
与AND reads.group_id = " . $group_id . "
这没什么区别,因为comments.group_id
总是等于$group_id
对于数据库来说,常量可能更容易匹配。但是,数据库可能已经在内部进行了这种优化,或者以一种无法利用这种优化的方式运行查询。主要问题:不要使用
.
操作员;相反,使用库或框架中的相关函数分别传递sql查询(带有占位符)和值(group_id
以及user_id
). 使用.
操作员非常危险。ki1q1bka4#
除了这里提到的所有答案之外,这里还有一个一般性的建议。
一
EXPLAIN
在一个SELECT
查询显示如何执行查询。即
EXPLAIN SELECT * FROM T1
现在,列键\u len显示一个索引项的大小(以字节为单位)。这个值越低,索引项就越多地适合相同的内存大小,处理它们的速度就越快。rows显示查询需要扫描的预期行数,越低越好。