有没有办法使这个查询更有效地表现?

时间:2014-02-26 12:39:25

标签: sql sql-server-2008

此查询需要很长时间才能在具有70GB数据的MS Sql 2008 DB上运行。 如果我单独运行2 where子句,则需要的时间少得多。

编辑 - 之后我需要将“选择*”更改为“删除”,请在回答时记住。谢谢:))

select *
From computers
Where Name in
      (
      select T2.Name
      from 
            (
            select Name
            from computers
            group by Name
            having COUNT(*) > 1
            ) T3 
      join computers T2 on T3.Name = T2.Name 
      left join policyassociations PA on T2.PK = PA.EntityId
      where (T2.EncryptionStatus = 0 or T2.EncryptionStatus is NULL) and 
            (PA.EntityType <> 1 or PA.EntityType is NULL)
      )
OR
      ClientId in
      (
      select substring(ClientID,11,100)
      from computers
      )

3 个答案:

答案 0 :(得分:0)

or有时可能无法进行优化。在这种情况下,您可以将查询拆分为两个子查询,并使用union组合它们:

select *
From computers
Where Name in
      (
      select T2.Name
      from 
            (
            select Name
            from computers
            group by Name
            having COUNT(*) > 1
            ) T3 
      join computers T2 on T3.Name = T2.Name 
      left join policyassociations PA on T2.PK = PA.EntityId
      where (T2.EncryptionStatus = 0 or T2.EncryptionStatus is NULL) and 
            (PA.EntityType <> 1 or PA.EntityType is NULL)
      )
UNION
select *
From computers
WHERE ClientId in
      (
      select substring(ClientID,11,100)
      from computers
      );

您也可以通过使用显式join替换子查询来提高性能。然而,这似乎是提高性能的最短途径。

编辑:

我认为加入的版本是:

select c.*
From computers c left outer join
     (select c.Name
      from (select c.*, count(*) over (partition by Name) as cnt
            from computers c
           ) c left join
           policyassociations PA
           on T2.PK = PA.EntityId and PA.EntityType <> 1
      where (c.EncryptionStatus = 0 or c.EncryptionStatus is NULL) and
            c.cnt > 1
     ) cpa
     on c.Name = cpa.Name left outer join
     (select substring(ClientID, 11, 100) as name
      from computers
     ) csub
     on c.Name = csub.name 
Where cpa.Name is not null or csub.Name is not null;

答案 1 :(得分:0)

IN交换EXISTS会有所帮助。 此外,根据戈登的回答:UNION可以胜过OR

SELECT computers.*
FROM   computers
 LEFT
  JOIN policyassociations
    ON policyassociations.entityid = computers.pk
WHERE  (
          computers.encryptionstatus = 0
       OR computers.encryptionstatus IS NULL
       )
AND    (
          policyassociations.entitytype <> 1
       OR policyassociations.entitytype IS NULL
       )
AND    EXISTS (
         SELECT name
         FROM   (
                 SELECT name
                 FROM   computers
                 GROUP
                     BY name
                 HAVING Count(*) > 1
                ) As duplicate_computers
         WHERE  name = computers.name
       )

UNION

SELECT *
FROM   computers As c
WHERE  EXISTS (
         SELECT SubString(clientid, 11, 100)
         FROM   computers
         WHERE  SubString(clientid, 11, 100) = c.clientid
       )

您现在已经更新了您的问题,要求将其删除。

好消息是,您只需要发出两个DELETE语句而不是“OR”:

DELETE
FROM   computers
 LEFT
  JOIN policyassociations
    ON policyassociations.entityid = computers.pk
WHERE  (
          computers.encryptionstatus = 0
       OR computers.encryptionstatus IS NULL
       )
AND    (
          policyassociations.entitytype <> 1
       OR policyassociations.entitytype IS NULL
       )
AND    EXISTS (
         SELECT name
         FROM   (
                 SELECT name
                 FROM   computers
                 GROUP
                     BY name
                 HAVING Count(*) > 1
                ) As duplicate_computers
         WHERE  name = computers.name
       )
;

DELETE
FROM   computers As c
WHERE  EXISTS (
         SELECT SubString(clientid, 11, 100)
         FROM   computers
         WHERE  SubString(clientid, 11, 100) = c.clientid
       )
;

答案 2 :(得分:0)

我要看的一些事情是 是否有指数?
2.“IN”会降低查询速度,尝试用连接替换它,
3.你应该使用列名,在这种情况下我猜是'Name',而使用count(*),
4.通过选择特定列,尝试仅选择所需数据。

希望这有帮助!