SQL Server:计数请求优化

Posted

技术标签:

【中文标题】SQL Server:计数请求优化【英文标题】:SQL Server: count request optimization 【发布时间】:2015-05-31 03:56:39 【问题描述】:

我正在寻找一种解决方案来优化我在一些大表上运行的选择查询(每个表超过 1 亿个项目),这是我正在使用的当前解决方案,它需要超过 40 分钟!

SELECT Count(a.id) 
FROM   tablea a 
       JOIN tableb b 
         ON a.ref_xid = b.xid 
            AND a.ref_yid = b.yid 
WHERE  ( b.filtre = 1 
          OR b.filtre = 7 ) 
       AND NOT EXISTS (SELECT id 
                       FROM   tablec 
                       WHERE  xid = a.xid 
                              AND yid = a.yid); 

【问题讨论】:

索引。索引。索引 【参考方案1】:

对于这个查询:

SELECT Count(a.id) 
FROM tablea a JOIN
     tableb b 
     ON a.ref_xid = b.xid AND a.ref_yid = b.yid 
WHERE b.filtre IN (1, 7) AND 
      NOT EXISTS (SELECT 1 
                  FROM   tablec c
                  WHERE  c.xid = a.xid AND c.yid = a.yid
                 ); 

您希望在tableb(filtre, xid, yid)tablea(ref_xid, ref_yid)tablec(xid, yid) 上建立索引。

【讨论】:

我已经在这些列上建立了索引,但还不够。 @Hisham 。 . .你有确切指定的三个索引,有 3 列、列和 2 列?【参考方案2】:

这里的问题并不是真正的查询,而是机器必须经过的 I/O 量。

SELECT Count(*) 
  FROM tablea a 
  JOIN tableb b 
    ON b.xid = a.ref_xid 
   AND b.yid = a.ref_yid
   AND b.filtre IN (1, 7) 
   AND NOT EXISTS (SELECT * 
                     FROM tablec c
                    WHERE c.xid = a.xid 
                      AND c.yid = a.yid); 

为了限制这一点,你应该

向表中添加(相关)索引,以确保您只需要遍历所需的记录 添加“覆盖”索引以确保在找到索引中的相关入口点时,服务器不需要返回表中的记录来找出需要的其他字段,但未纳入索引

至于您给出的示例,我想说您需要以下索引才能获得最佳性能为此查询:

CREATE INDEX idx_filtre ON tableb (filtre) INCLUDE (xid, yid)
CREATE INDEX idx_ids    ON tablec (xid, yid)
CREATE INDEX idx_refids ON tablea (ref_xid, ref_yid) INCLUDE (xid, yid)

(我假设所有表在 id 字段上都已经有一个聚集的 PK)

PS:查询执行计划是你的朋友。

【讨论】:

感谢大家的回答和建议,最终使用的解决方案是临时表,每次仅应用一个过滤器。为此需要 5 个表,但最终结果要好得多。我可以考虑从我这边结束问题。【参考方案3】:

最终可行的解决方案是使用临时表并将请求分为 2 个步骤。 第一个仅在临时表中准备数据,第二个用于处理临时表并应用更改。

【讨论】:

【参考方案4】:

你可以使用临时表:

;
WITH    q1
          AS ( SELECT   *
               FROM     tableB b
               WHERE    b.filtre = 1
                        OR b.filtre = 7
             ),
        q2
          AS ( SELECT   *
               FROM     tableA a
               WHERE    NOT EXISTS ( SELECT id
                                     FROM   tableC
                                     WHERE  xid = a.xid
                                            AND yid = a.yid )
             )
    SELECT  COUNT(a.id)
    FROM    tableA a
            JOIN tableB b ON a.ref_xid = b.xid
                             AND a.ref_yid = b.yid

【讨论】:

你想写这个吗? SELECT COUNT(a.id) FROM q2 a JOIN q1 b ON a.ref_xid = b.xid AND a.ref_yid = b.yid 但是使用 COUNt(a.id) 还是 Count(*) 更好? 你为什么建议使用临时表,然后用 CTE 展示一个例子?到目前为止,CTE 基本上没有临时表,只是子查询的不同语法。 我们最好限制将要连接在一起的数据以优化查询。所以我使用'CTE'来做到这一点。这里的主要成本是加入,而在第二级 count() 成本很高。

以上是关于SQL Server:计数请求优化的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server 数据库性能优化

SQL Server 数据库性能优化

[转] SQL Server 数据库性能优化

优化 sql 计数查询

优化视图引用 SQL Server 中的视图的策略?

如何优化访问计数器 SQL 查询?