有没有办法优化这个查询

Posted

技术标签:

【中文标题】有没有办法优化这个查询【英文标题】:Is there a way to optimize this query 【发布时间】:2019-11-26 18:42:19 【问题描述】:

我已经写了一个查询,但它需要很多时间。我想知道是否存在任何解决方案来优化它而不在 mysql 中创建临时表。有没有办法优化子查询部分,因为 AccessLog2019 很大,所以它需要永远)

这是我的查询

SELECT distinct l.ListingID,l.City,l.ListingStatus,l.Price,l.Bedrooms,l.FullBathrooms, gc.Latitude,gc.Longitude , count(distinct s.AccessLogID) AS access_count, s.LBID , lb.CurrentListingID
from lockbox.Listings l 
JOIN lockbox.GeoCoordinates gc ON l.ListingID = gc.ID
LEFT JOIN lockbox.LockBox lb ON l.ListingID = lb.CurrentListingID
LEFT JOIN
(SELECT  * FROM  lockbox.AccessLog2019 ac where ac.AccessType not in('1DayCodeGen','BluCodeGen','SmartMACGen') AND  DATEDIFF(NOW(), ac.UTCAccessedDT ) < 1 ) s
ON lb.LBID = s.LBID
WHERE  l.AssocID = 'AS00000000CC' AND  (gc.Confidence  <> '5 - Unmatchable' OR  gc.Confidence  IS NULL OR gc.Confidence = ' ') 
group BY l.ListingID

谢谢

【问题讨论】:

您需要来自AccessLog2019* 吗?您还索引了表格吗? 仅供参考,许多 Stack Overflow 回答者甚至不会查看查询优化问题,除非您为查询中的每个表共享 (a) SHOW CREATE TABLE &lt;tablename&gt;\G 的输出,(b) EXPLAIN 对于查询,以及 (c) SHOW TABLE STATUS LIKE '&lt;tablename&gt;'\G 查询中的每个表。 添加到@BillKarwin 的评论,然后我们也可以验证这里是否正确使用了 GROUP BY,这似乎是非标准的(SQL 1992) GROUP BY 用法,并且仅在运行时有效在 MySQL 5.7.5+ 支持的 SQL 1999+ 标准上(启用 ONLY_FULL_GROUP_BY sql_mode)称为functional dependency.. .. 如前所述,您的日期计算不能使用函数,但可以重新排列该部分 要详细说明@PritamBanerjee 的评论,您可能想尝试在 AccessType 上为 table lockbox.AccessLog2019 添加一个索引,以帮助“哪里不在...” 【参考方案1】:

如果你能避开外部的group by,那就是一个巨大的胜利。我在想:

SELECT l.ListingID, l.City, l.ListingStatus, l.Price, l.Bedrooms, l.FullBathrooms,
       gc.Latitude, gc.Longitude,
       (select count(*)
        from lockbox.LockBox lb join
             lockbox.AccessLog2019 ac
             on lb.LBID = ac.LBID       
        where l.ListingID = lb.CurrentListingID and
              ac.AccessType not in ('1DayCodeGen', 'BluCodeGen', 'SmartMACGen') and
              DATEDIFF(NOW(), ac.UTCAccessedDT) < 1
       ) as cnt
from lockbox.Listings l JOIN
     lockbox.GeoCoordinates gc
     ON l.ListingID = gc.ID
WHERE l.AssocID = 'AS00000000CC' AND
      (gc.Confidence  <> '5 - Unmatchable' OR 
       gc.Confidence  IS NULL OR
       gc.Confidence = ' '
      ) 

注意:这不会选择 s.LBIDlb.CurrentListingID,因为它们在您的查询中没有意义。如果我理解正确,这些可能在不同的行上有不同的值。

【讨论】:

【参考方案2】:

您可以尝试将子查询拆分为 JOIN 子句。

它可能会向优化器提示它可以先使用 LBID 字段,然后再测试 AccessType(以防优化器在您有子选择时没有弄清楚)。

SELECT distinct l.ListingID,l.City,l.ListingStatus,l.Price,l.Bedrooms,l.FullBathrooms, gc.Latitude,gc.Longitude , count(distinct s.AccessLogID) AS access_count, s.LBID , lb.CurrentListingID
from lockbox.Listings l 
JOIN lockbox.GeoCoordinates gc ON l.ListingID = gc.ID
LEFT JOIN lockbox.LockBox lb ON l.ListingID = lb.CurrentListingID
LEFT JOIN AccessLog2019 s
ON lb.LBID = s.LBID
   AND s.AccessType not in('1DayCodeGen','BluCodeGen','SmartMACGen')
   AND DATEDIFF(NOW(), s.UTCAccessedDT ) < 1
WHERE  l.AssocID = 'AS00000000CC' AND  (gc.Confidence  <> '5 - Unmatchable' OR  gc.Confidence  IS NULL OR gc.Confidence = ' ') 
group BY l.ListingID

请注意,这是 JOIN 子句中的条件给出的行为与使用 WHERE 子句不同的情况之一。如果你只有lb.LBID = s.LBID,然后有我在外部查询的WHERE 中写的条件,结果会有所不同。他们将排除匹配lb.LBID = s.LBID 的记录。但是在JOIN子句中,它是外连接条件的一部分。

【讨论】:

这似乎是非标准(SQL 1992)GROUP BY 用法,并且仅在 MySQL 5.7.5+ 支持的 SQL 1999+ 标准上运行时有效(启用 ONLY_FULL_GROUP_BY sql_mode),称为@ 987654321@ ...换句话说,此查询可以给出的结果可能是无效的,因为每个组的不相关值... @RaymondNijland 是的,我注意到 mysql 支持非标准 SQL 功能,即使用主键进行分组,而不列出所有字段。 “是的,我注意到mysql支持一个非标准的SQL特性,即使用主键进行分组” 嗯,函数依赖实际上定义为ANSI/ISO SQL 99 中的>可选功能 ... 不知道 ANSI/ISO SQL 标准是否会更进一步,然后 MySQL 支持在运行时查找功能依赖项(这意味着使用 DISTINCT 运行的查询作为简单示例)和不超出唯一表约束而已..【参考方案3】: SELECT * --> 只选择需要的列。 SELECT DISTINCT ... GROUP BY -- 做一个或另一个,而不是两个。 需要复合INDEX(AssocID, ListingID)(按此顺序) DATEDIFF(NOW(), ac.UTCAccessedDT ) &lt; 1 --> ac.UTCAccessedDT &gt; NOW() - INTERVAL 1 DAY (或任何你的意图。然后添加INDEX(UTCAccessedDT) OR 难以优化;考虑清理数据,使 Confidence 没有 3 个值表示相同的含义。

【讨论】:

以上是关于有没有办法优化这个查询的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法优化这个mysql查询?

条件检查之间的Mysql中有多个条件?有没有办法优化这个查询?

有没有办法提高这个简单的 WordPress 数据库查询的性能?

有没有办法组合 mysqli 查询或给它们一个优化序列?

如何优化这个 sql 查询(内连接)

我的Myqls数据库中有2个数据表,每个数据表都有超过3千万条记录,查询效率很低,有没有什麽好的办法优化?