如何优化长期运行的查询?

时间:2018-11-08 17:00:55

标签: sql sql-server

我有一个查询,它消耗大量CPU,导致某些超时:

select cast(count(*) as INT) as colCount 
from TableGR tgr 
where ((tgr.OriginCode is not null) 
        and (tgr.OriginCode in (@p0 , @p1 , @p2 , @p3)) 
        or tgr.Type=@p4 
        and (tgr.OriginVat in (@p5 , @p6 , @p7 , @p8)) 
        or (tgr.DestinCode is not null) 
        and (tgr.DestinCode in (@p9 , @p10 , @p11 , @p12)) 
        or (exists (select t1.Id 
                  from Transporters t1 
                  where tgr.GarId=t1.GarId)) 
        and (exists (select t2.Id 
                   from Transporters t2 
                   where tgr.GarId=t2.GarId and (t2.Vat in (@p13 , @p14 , @p15 , @p16))))
     ) 
     and (tgr.DeletedUtc is null);

我想查询是执行多个子查询的原因,因此我考虑向表TableGR添加新列,以包含用逗号分隔的字符串t1.Id和t2.Id。我考虑的另一种选择是在表TableGR中添加两个新列(列t1Id,t2Id)。

2 个答案:

答案 0 :(得分:0)

您可以将查询更改为使用联接,而不是使用联接来优化查询。

  

我考虑将新列添加到表TableGR中,以包含一个逗号分隔的字符串,其中包含t1.Id和t2.Id`

    不好的主意。
  

我考虑的另一种选择是在表TableGR中添加两个新列(列t1Id,t2Id)

  • 这也可能有效。

有太多可能的优化方法,根据您的数据,这些优化方法可能会也可能无法帮助您。这就是为什么最好使用view query execution plan

查看执行查询所花费的时间最多的时间

答案 1 :(得分:0)

如果重新格式化您的查询,可以看到它是由许多不同列上的搜索组成的。这使得优化器很难利用任何索引。

select
  cast(count(*) as INT) as colCount 
from
  TableGR tgr 
where
(
    (tgr.OriginCode is not null) 
and (tgr.OriginCode in (@p0 , @p1 , @p2 , @p3)) 

or
    tgr.Type=@p4 
and (tgr.OriginVat in (@p5 , @p6 , @p7 , @p8))

or

    (tgr.DestinCode is not null) 
and (tgr.DestinCode in (@p9 , @p10 , @p11 , @p12))

or

    (exists (select t1.Id from Transporters t1 where tgr.GarId=t1.GarId)) 
and (exists (select t2.Id from Transporters t2 where tgr.GarId=t2.GarId and (t2.Vat in (@p13 , @p14 , @p15 , @p16))))
) 
and
  (tgr.DeletedUtc is null);

一种 的缓解方法是将其分解为可以使用表索引的简单查询。

(我将x IS NOT NULL AND x IN (a,b,c)简化为x IN (a,b,c),因为如果x为null,则它永远不会出现在任何列表中……)

SELECT
  COUNT(*)   AS colCount
FROM
(
  -- Could use an index on (DeletedUtc, OriginCode)
  SELECT PrimaryKeyColumn
    FROM TableGR tgr 
   WHERE tgr.DeletedUtc IS NULL
     AND tgr.OriginCode in (@p0 , @p1 , @p2 , @p3)

  UNION

  -- Could use an index on (DeletedUtc, Type, OriginCode)
  SELECT PrimaryKeyColumn
    FROM TableGR tgr 
   WHERE tgr.DeletedUtc IS NULL
     AND tgr.Type=@p4 
     AND tgr.OriginVat in (@p5 , @p6 , @p7 , @p8)

  UNION

  -- Could use an index on (DeletedUtc, DestinCode)
  SELECT PrimaryKeyColumn
    FROM TableGR tgr 
   WHERE tgr.DeletedUtc IS NULL
     AND tgr.DestinCode in (@p9 , @p10 , @p11 , @p12)

  UNION

  -- Could use an index on (DeletedUtc, GarID)
  SELECT PrimaryKeyColumn
    FROM TableGR tgr 
   WHERE tgr.DeletedUtc IS NULL
      -- Why the Two EXISTS() expressions here?  If the second is TRUE the first is always also TRUE, no?
     AND (exists (select t1.Id from Transporters t1 where tgr.GarId=t1.GarId)) 
     AND (exists (select t2.Id from Transporters t2 where tgr.GarId=t2.GarId and (t2.Vat in (@p13 , @p14 , @p15 , @p16))))
)
  AS targets

请注意,我使用的是UNION而不是UNION ALL。这是为了防止一行可以满足一项条件UNION“对数据进行重复数据删除”,从而防止对一行进行多次计数。)

如果您 知道 ,任何一行只能出现在 查询中,请使用{{ 1}}。

然后返回您的执行计划,看看是否还有其他索引或其他优化可能会有所帮助。