优化给定的 sql 查询以提高速度

Posted

技术标签:

【中文标题】优化给定的 sql 查询以提高速度【英文标题】:optimize given sql query for speed 【发布时间】:2021-11-02 12:06:19 【问题描述】:

我从一位程序员同事那里得到了这个查询,但它执行得非常慢。运行大约需要 4 秒。

能否优化此查询以提供相同的结果,但性能更好?

SELECT checkedcrates, 
   pv.name as powervision, 
   cg.name as cgrp, 
   cs.name as csz, 
   c.name as cname
   FROM  public.inspectionresultsstatistic e, 
        crates c, 
        powervisions pv, 
        lines l, 
        quality q, 
        cratesgroupscrates cgc, 
        cratesgroups cg, 
        cratessizes cs 
   where
        c.id = e.crateid 
        and l.id = e.lineid 
        and pv.id = l.powervisionid
        and q.id = e.qualityid 
        and c.id = cgc.crateid 
        and cs.id = cgc.cratesizeid 
        and cg.id = cgc.crategroupid 
        and qualityid = 0
        and pv.name in ('PV101')  
        and c.name in ('24603','104','136','154','186','106','156','216','246','206')
        and cg.name in ('Black','Blue','DLL','Green')
        and cs.name in ('30x40','60x40')
        and to_timestamp(e.startts) >= '2021-10-18T17:45:22Z' 
        and to_timestamp(e.stopts-1) <= '2021-10-18T19:45:22Z'
   group by 
     powervision, 
     cgrp, 
     csz, 
     cname, 
     checkedcrates, 
     startts
 

编辑:实际上只是注意到内部选择很慢...通过删除外部查询更新了上面的查询

EDIT2:也许我应该添加一些索引?我为每个连接到另一个表的表(所以所有 ID 列)都有一个索引,并且对于检查结果统计有一个 id + qualityid + startts + stopts 的索引

EDIT3:根据要求,我尝试提供有关我的表格和数据的更多信息。

我正在使用 PostgreSql 12,

表结构如下:

http://sqlfiddle.com/#!17/bb5a6/1

除了包含大约 12.000.000 行的inspectionresultsstatistics 之外,所有表都相当小,条目少于50 个。

【问题讨论】:

这里的优化路径是为您的表添加有用的索引。为了帮助您解决这个问题,我们需要更多信息。请使用您使用的 DBMS 标记您的问题(oracle、mysql、sql-server、postgresql)。并且,请read this,然后edit 你的问题。 构造 to_timestamp(column) 通过使 WHERE 子句 non-sargable 来击败 column 上的任何索引。如果不了解列的数据类型,就不可能给你体面的建议。 @O.Jones 好的,谢谢,尽快更新。 to_timestamp 问题是否有解决方法?这可以放在等式的右边吗? 是的,to_timestamp() 子句可以重构。但并非不知道这些列中的内容。 @O.Jones 我更新了帖子,使用包含所有表的 SQL 小提琴。所有表都相当小,条目少于 50 个,但包含大约 12.000.000 行的inspectionresultsstatistics 除外。 【参考方案1】:

我最大的特点是你的连接不是用更新的语法编写的。当您在 FROM 子句中的表之间使用逗号时,它会创建两个表的“笛卡尔积”。这比使用 'INNER JOIN' 后跟 'ON' 子句更耗费资源。应使用 ON 子句代替 WHERE 子句中的约束。

类似的,

   SELECT checkedcrates, 
    pv.name as powervision, 
    cg.name as cgrp, 
    cs.name as csz, 
    c.name as cname
FROM  public.inspectionresultsstatistic e
    INNER JOIN crates c
        ON c.id = e.crateid 
    INNER JOIN lines l
        ON l.id = e.lineid 
    INNER JOIN powervisions pv
        ON pv.id = l.powervisionid
    INNER JOIN quality q
        ON q.id = e.qualityid
    INNER JOIN cratesgroupscrates cgc
        ON c.id = cgc.crateid
    INNER JOIN cratesgroups cg
        ON cg.id = cgc.crategroupid
    INNER JOIN cratessizes cs 
        ON cs.id = cgc.cratesizeid
where qualityid = 0
    and pv.name in ('PV101')  
    and c.name in ('24603','104','136','154','186','106','156','216','246','206')
    and cg.name in ('Black','Blue','DLL','Green')
    and cs.name in ('30x40','60x40')
    and to_timestamp(e.startts) >= '2021-10-18T17:45:22Z' 
    and to_timestamp(e.stopts-1) <= '2021-10-18T19:45:22Z'
group by 
    powervision, 
    cgrp, 
    csz, 
    cname, 
    checkedcrates, 
    startts

【讨论】:

实际上,Oracle 基于成本的查询计划器使用 WHERE 子句中的连接条件识别和处理您祖父的逗号连接,其性能与使用 ON 子句的连接相同。 ON 子句仍然更容易阅读。 感谢您的回答。我只是尝试运行您的查询,它需要相同的时间。也许我应该创建一些索引?我应该创建哪些索引来加速这个特定的查询? (更新问题以包括此) @O.Jones 这就是为什么 Oracle 的每个核心是 5 位数!我已经看到使用 SQL Server 显着提高了性能,但在这种情况下似乎没有帮助:( 其他 DBMS 品牌和模型也可以有效地处理逗号连接语法,包括 sql-server、mysql 和 postgresql。你说得对,Oracle 的价格高得惊人。 规划者对 WHERE 中的连接条件没有任何问题。编写和读取查询的人受益于将连接分解为显式 ON。【参考方案2】:

您的小提琴不包括索引。您应该使用 db-fiddle.com 而不是 sqlfiddle,因为后者本质上已经损坏,没有比 9.6 更新的版本。

被查询的时间范围很小,所以想必是很有选择性的。

您最好将其作为一个范围进行查询:

and tstzrange(to_timestamp(e.startts),to_timestamp(e.stopts-1),'[]') <@ 
    tstzrange('2021-10-18T17:45:22Z','2021-10-18T19:45:22Z','[]')

这将受益于表达式索引

on inspectionresultsstatistic using gist (tstzrange(to_timestamp(startts),to_timestamp(stopts-1),'[]'))

但实际上,最好将时间戳存储为 timestamptz 而不是 int8,或者甚至直接将它们存储为 tstzrange。

【讨论】:

以上是关于优化给定的 sql 查询以提高速度的主要内容,如果未能解决你的问题,请参考以下文章

优化 sql 查询以提高效率

如何提高oracle的查询速度

如何提高sql查询速度

SQL 百万级数据提高查询速度的方法

优化我的 T-SQL 查询以提高性能

如何解决SQL Server查询速度缓慢的问题