sql查询不是很慢

gajydyqb  于 2021-08-09  发布在  Java
关注(0)|答案(4)|浏览(305)

我正在尝试优化一个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

有索引相关的字段和表是相当大的。

z3yyvxxp

z3yyvxxp1#

作为启动器,此条件:

DATE(created_on) > DATE_SUB(CURDATE(), INTERVAL 1 DAY)

应重写为:

created_on >= current_date

这在功能上是等价的,不在被筛选的列上使用日期函数会使数据库有机会使用索引。
然后,考虑以下指标:

comments(group_id, created_on, user_id)
reads(notification_id, group_id, user_id, notification_type, created_on)

这是两个多列索引(称为复合索引),而不是每列上的单独索引。你会注意到它们与 where 查询和子查询的 predicate 。索引中列的顺序很重要(尤其是在 comments ):首先需要具有相等 predicate 的列,然后是具有不等 predicate 的列。
最后:你真的需要吗 select * ? 最好将列表缩小到实际需要的列;如果只有几个,您可能需要尝试将它们添加到上的索引中 comments .
旁注: limit 没有 order by 通常没有用。这将为您提供一组任意的匹配行,并且在同一数据集上连续执行同一查询的结果可能不一致
考虑使用准备好的语句,而不是在查询字符串中串联变量;这使得mysql能够识别查询,并重用已经准备好的执行计划(这是一个很小的收获,但总是很好的),而且,更重要的是,它可以防止sql注入。

o2g1uqev

o2g1uqev2#

对于您的查询,您需要索引:
comments(group_id, created_on, user_id) reads(post_id, group_id, notification_type, user_id, created_on) .
这是你的两个索引吗?

wsewodh2

wsewodh23#

微小的潜在改进,替换条款 AND comments.group_id = reads.group_idAND reads.group_id = " . $group_id . " 这没什么区别,因为 comments.group_id 总是等于 $group_id 对于数据库来说,常量可能更容易匹配。但是,数据库可能已经在内部进行了这种优化,或者以一种无法利用这种优化的方式运行查询。
主要问题:不要使用 . 操作员;相反,使用库或框架中的相关函数分别传递sql查询(带有占位符)和值( group_id 以及 user_id ). 使用 . 操作员非常危险。

ki1q1bka

ki1q1bka4#

除了这里提到的所有答案之外,这里还有一个一般性的建议。
EXPLAIN 在一个 SELECT 查询显示如何执行查询。
EXPLAIN SELECT * FROM T1 现在,列键\u len显示一个索引项的大小(以字节为单位)。这个值越低,索引项就越多地适合相同的内存大小,处理它们的速度就越快。rows显示查询需要扫描的预期行数,越低越好。

相关问题