【问题标题】:SQL query NOT EXIST very slowSQL查询不存在非常慢
【发布时间】:2020-06-08 23:44:47
【问题描述】:

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

相关字段有索引,表很大。

【问题讨论】:

    标签: mysql sql select query-optimization


    【解决方案1】:

    首先,这个条件:

    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 谓词相匹配。索引中列的顺序很重要(尤其是在comments 上的索引中):您希望列首先具有相等谓词,然后是具有不等谓词的列。

    最后:你真的需要select *吗?最好将列表减少到您实际需要的列;如果只有几个,您可能想尝试将它们添加到 comments 上的索引中。

    旁注:

    • limit 没有order by 通常没有用处。这为您提供了匹配的行中的任意行集 - 并且在同一数据集上连续执行同一查询时,结果可能不一致

    • 考虑使用准备好的语句,而不是在查询字符串中连接变量;这允许 MySQL 识别查询,并重用已经准备好的执行计划(这是一个很小的收获,但总是很好) - 更重要的是,它可以防止 SQL 注入。

    【讨论】:

    • 哇,伙计!只是 created_on >= current_date 有很大的不同!感谢您的扩展建议!
    【解决方案2】:

    对于您的查询,您需要以下索引:

    • comments(group_id, created_on, user_id)
    • reads(post_id, group_id, notification_type, user_id, created_on).

    这是你拥有的两个索引吗?

    【讨论】:

    • 嗨@Gordon,是的,站点列的索引存在
    • @ABMoslih 。 . .不是索引。这两个特定的索引。
    【解决方案3】:
    • 潜在的小改进,将子句 AND comments.group_id = reads.group_id 替换为 AND reads.group_id = " . $group_id . "

      这没有什么区别,因为comments.group_id 已经总是等于$group_id 并且数据库可能更容易匹配该常量。但是,数据库可能已经在内部进行此优化,或者以无法利用此优势的方式运行查询。

    • 主要问题:不要使用. 运算符构造查询;相反,使用库或框架中的相关函数分别传递 SQL 查询(带占位符)和值(group_iduser_id)。使用. 运算符构造查询非常危险。

    【讨论】:

      【解决方案4】:

      除了这里提到的所有答案之外,这里还有一个一般性建议。

      SELECTquery 前面的 EXPLAIN 显示查询将如何执行。

      EXPLAIN SELECT * FROM T1

      现在,key_len 列显示了一个索引项的大小(以字节为单位)。该值越低,相同内存大小的索引项越多,处理速度越快。 行数显示查询需要扫描的预期行数,越低越好。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-16
        • 1970-01-01
        • 1970-01-01
        • 2015-09-02
        • 2014-07-23
        相关资源
        最近更新 更多