更高效的SQL Server语句

时间:2012-01-13 17:00:50

标签: sql sql-server

我想知道如何提高SQL语句的性能和效率。 有没有人有一些想法或建议?

DECLARE @RoleName NVARCHAR(MAX)
DECLARE @result INT

SELECT @result = COUNT(DurchlaufVorgang.Durchlaufname)
FROM   DurchlaufVorgang
INNER JOIN RoleDepartment
        ON DurchlaufVorgang.AbteilungID = RoleDepartment.ID
WHERE  DurchlaufVorgang.Depricated = 'FALSE'
       AND RoleDepartment.RoleName = @RoleName
       AND RoleDepartment.Depricated = 'FALSE'

SELECT Antraege.AntragID
FROM   ArtikelMitteilung,
       Antraege
WHERE  ArtikelMitteilung.Status = 'Opened'
       AND Antraege.AntragID NOT IN 
          (SELECT Antraege.AntragID
           FROM   Vorgang,
                  Antraege
           WHERE  Vorgang.StepID IN 
                  (SELECT DurchlaufVorgang.ID
                   FROM   DurchlaufVorgang
                   INNER JOIN RoleDepartment
                           ON DurchlaufVorgang.AbteilungID = RoleDepartment.ID
                   WHERE DurchlaufVorgang.Depricated = 'FALSE'
                     AND RoleDepartment.RoleName = @RoleName
                     AND RoleDepartment.Depricated = 'FALSE')
              AND Vorgang.AntragsID = Antraege.ID
            GROUP  BY Antraege.AntragID
            HAVING COUNT(Antraege.AntragID) >= @result)
       AND ArtikelMitteilung.AntragsID = Antraege.ID
GROUP  BY Antraege.AntragID  

我很感谢你的帮助。

4 个答案:

答案 0 :(得分:1)

查看实际的查询计划,并查看索引扫描和表扫描的位置。找到使用索引寻求消除这些瓶颈的方法。

我可能会猜测你所拥有的所有谓词都没有编入索引,也许最有选择性的谓词可能被编入索引,这将极大地帮助查询计划程序选择索引寻求识别要返回的行。

您还可以尝试在WHERE子句中使用NOT EXISTS表单而不是NOT IN表单。有时这可能有所帮助,您应该运行检查每个查询执行计划。

编辑:

同时删除冗余代码。例如,

      (SELECT Antraege.AntragID
       FROM   Vorgang,
              Antraege
       WHERE  Vorgang.StepID IN 
              (/* your subquery */)
          AND Vorgang.AntragsID = Antraege.ID
        GROUP  BY Antraege.AntragID
        HAVING COUNT(Antraege.AntragID) >= @result)

可以简化:

      (SELECT Vorgang.AntragsID
       FROM   Vorgang
       WHERE  Vorgang.StepID IN 
              (/* your subquery */)
        GROUP  BY Vorgang.AntragsID
        HAVING COUNT(Vorgang.AntragsID) >= @result)

答案 1 :(得分:1)

你的查询中没有做任何明显错误的事情。 SQL优化器将采用类似的大型语句,并找出执行它的最佳方法。如果你的指数碎片化或不存在,你可能遇到问题的地方。

从SQL Server Management Studio中,单击“显示执行计划”,然后查看是否建议任何其他索引。对索引进行解组(如果您处于测试环境中,则可以删除并重新添加它们)。

如果你的直觉是一个大的声明对性能不利,那么这不应该是这种情况。事实上,它应该有助于优化器,因为它为如何执行它提供了更多选择。

答案 2 :(得分:1)

取决于表的大小,将列表放入索引列可能会有很大帮助。

declare @tab (AntragID int primary key clustered)
insert @tab
(AntragID)
SELECT Antraege.AntragID 
           FROM   Vorgang, 
                  Antraege 
           WHERE  Vorgang.StepID IN  
                  (SELECT DurchlaufVorgang.ID 
                   FROM   DurchlaufVorgang 
                   INNER JOIN RoleDepartment 
                           ON DurchlaufVorgang.AbteilungID = RoleDepartment.ID 
                   WHERE DurchlaufVorgang.Depricated = 'FALSE' 
                     AND RoleDepartment.RoleName = @RoleName 
                     AND RoleDepartment.Depricated = 'FALSE') 
              AND Vorgang.AntragsID = Antraege.ID 
            GROUP  BY Antraege.AntragID 
            HAVING COUNT(Antraege.AntragID) >= @result


SELECT Antraege.AntragID 
FROM   
       Antraege
       INNER JOIN ArtikelMitteilung
         ON Antraege.ID = ArtikelMitteilung.AntragsID 
       LEFT JOIN @tab x
           ON Antraege.AntragID = X.AntragID
WHERE
    ArtikelMitteilung.Status = 'Opened' AND
    X.AntragID IS NULL  
GROUP BY

如果未从子查询返回唯一的AntragID,则使用临时表而不是表变量,并在AntragID上创建索引。

create table #tab (AntragID int)  
create clustered index cix_antragid_tab on #tab(AntragID)


insert #tab
(AntragID)
SELECT Antraege.AntragID 
           FROM   Vorgang, 
                  Antraege 
           WHERE  Vorgang.StepID IN  
                  (SELECT DurchlaufVorgang.ID 
                   FROM   DurchlaufVorgang 
                   INNER JOIN RoleDepartment 
                           ON DurchlaufVorgang.AbteilungID = RoleDepartment.ID 
                   WHERE DurchlaufVorgang.Depricated = 'FALSE' 
                     AND RoleDepartment.RoleName = @RoleName 
                     AND RoleDepartment.Depricated = 'FALSE') 
              AND Vorgang.AntragsID = Antraege.ID 
            GROUP  BY Antraege.AntragID 
            HAVING COUNT(Antraege.AntragID) >= @result


SELECT Antraege.AntragID 
FROM   
       Antraege
       INNER JOIN ArtikelMitteilung
         ON Antraege.ID = ArtikelMitteilung.AntragsID 
       LEFT JOIN #tab x
           ON Antraege.AntragID = X.AntragID
WHERE
    ArtikelMitteilung.Status = 'Opened' AND
    X.AntragID IS NULL  
GROUP BY

如果你发布了exec计划,那么可以优化查询的逻辑。

答案 3 :(得分:-1)

NOT IN条款往往效率不高。尝试使用LEFT JOIN代替。然后测试连接表(右侧)中的AntragID是否为空。

SELECT *
FROM
   Antrage A
   LEFT JOIN Antrage B
      ON A.AntragID = B.AntragID
WHERE
   B.AntragID IS NULL AND
   ...

SELECT Antraege.AntragID 
FROM   
       Antraege
       INNER JOIN ArtikelMitteilung
         ON Antraege.ID = ArtikelMitteilung.AntragsID 
       LEFT JOIN
          (SELECT Antraege.AntragID 
           FROM   Vorgang, 
                  Antraege 
           WHERE  Vorgang.StepID IN  
                  (SELECT DurchlaufVorgang.ID 
                   FROM   DurchlaufVorgang 
                   INNER JOIN RoleDepartment 
                           ON DurchlaufVorgang.AbteilungID = RoleDepartment.ID 
                   WHERE DurchlaufVorgang.Depricated = 'FALSE' 
                     AND RoleDepartment.RoleName = @RoleName 
                     AND RoleDepartment.Depricated = 'FALSE') 
              AND Vorgang.AntragsID = Antraege.ID 
            GROUP  BY Antraege.AntragID 
            HAVING COUNT(Antraege.AntragID) >= @result) X
              ON Antraege.AntragID = X.AntragID
WHERE
    ArtikelMitteilung.Status = 'Opened' AND
    X.AntragID IS NULL  
GROUP BY
    Antraege.AntragID