开发代码 - 了解我的看法

时间:2011-07-25 05:18:42

标签: sql-server-2008

这是我开始说我不是开发人员的地方,这不是我的代码。作为DBA,尽管它从性能角度出现在板上。执行计划向我显示,Table2的CI扫描别名为D,Table2别名为E.关注表2别名为E.扫描来自E.SEQ_NBR =的where子句中的子查询 我也看到了比需要更多的处决。我知道它取决于表格上的确切索引结构,但在很高的层次上,我所看到的可能是它发现的每个匹配的聚合(min)导致的CI扫描。基本上它是在EMPLID和其他领域的每个匹配的最小SEQ_NBR的桌子上走?

如果可能的话,是否更多地是由于它的编写方式(我认为将CTE与一些ROW_NUMBER逻辑结合起来会有所帮助)或缺乏索引?我试图避免抛出一个索引“只是因为”。我在where子句中挂起了那个子查询。

SELECT
    D.EMPLID
   ,D.JOBCODE
   ,D.DEPTID
   ,E.DUR
   ,SUM(D.TL_QUANTITY) 'YTD_TL_QUANTITY'
FROM
    Table1 B
   ,Table2 D
   ,Table2 E
WHERE
    D.TRC = B.TRC
    AND B.TL_ERNCD IN ( @0, @1, @2, @3, @4, @5, @6 )
    AND D.EMPLID = E.EMPLID
    AND D.EMPL_RCD = E.EMPL_RCD
    AND D.DUR < = E.DUR
    AND D.DUR > = '1/1/' + CAST(DATEPART(YEAR, E.DUR) AS CHAR)
    AND E.SEQ_NBR = 
                ( SELECT
                    MIN(EX.SEQ_NBR)
                  FROM
                    Table2 EX
                  WHERE
                    E.EMPLID = EX.EMPLID
                    AND E.EMPL_RCD = EX.EMPL_RCD
                    AND E.DUR = EX.DUR
                )
    AND B.EFFDT = ( SELECT
                        MAX(B_ED.EFFDT)
                    FROM
                        Table1 B_ED
                    WHERE
                        B.TRC = B_ED.TRC
                        AND B_ED.EFFDT < = GETDATE()
                  )
GROUP BY
    D.EMPLID
   ,D.JOBCODE
   ,D.DEPTID
   ,E.DUR

3 个答案:

答案 0 :(得分:1)

MIN操作与CL扫描无关。使用排序计算MIN或Max。问题很可能是子查询执行的次数。它必须遍历父查询中返回的每个记录的子查询。 CTE在这里可能会有所帮助,具体取决于Table2的大小,但我认为你不必担心找到MIN()的替代品......至少还没有。

答案 1 :(得分:1)

相关子查询是性能杀手。删除它们并用CTE和JOIN或派生表替换它们。

尝试这样的事情(未经测试)

SELECT
     D.EMPLID
     ,D.JOBCODE    
     ,D.DEPTID    
     ,E.DUR    
     ,SUM(D.TL_QUANTITY) 'YTD_TL_QUANTITY' 
FROM Table1 B    
JOIN Table2 D 
    ON D.TRC = B.TRC  AND D.EMPLID = E.EMPLID
JOIN Table2 E 
    ON D.EMPL_RCD = E.EMPL_RCD AND D.DUR < = E.DUR 
JOIN (SELECT MIN(EX.SEQ_NBR)FROM  Table2) EX 
    ON E.EMPLID = EX.EMPLID  
    AND E.EMPL_RCD = EX.EMPL_RCD                     
    AND E.DUR = EX.DUR  
JOIN (SELECT  MAX(B_ED.EFFDT)  
        FROM  Table1
        WHERE B_ED.EFFDT < = GETDATE()) B_ED 
    ON B.TRC = B_ED.TRC         
WHERE     B.TL_ERNCD IN ( @0, @1, @2, @3, @4, @5, @6 )           
AND D.DUR > = '1/1/' + CAST(DATEPART(YEAR, E.DUR) AS CHAR)  

就隐式连接语法而言,不允许任何人再次执行此操作。这是一种糟糕的编程技术。作为DBA,您可以说出您将在数据库中使用和不允许的内容。代码审查了什么,并且在它们删除隐式语法之前不会传递它。

为什么不好?首先,你会偶然发生交叉连接。此外,从维护的角度来看,您无法判断交叉连接是偶然的(因此查询不正确)还是故意的。这意味着在其中具有交叉连接的查询是不可维护的。

接下来,如果您必须稍后将某些连接更改为外连接并且不同时修复所有连接,则可能会得到不正确的结果(没有经验的开发人员可能会注意到这一点。在SQL Server中2008年你不能使用隐式语法进行外部联接,但它甚至不应该像SQl Server 2000那样被使用,因为联机丛书(对于SQL Server 2000)表明存在被误解的情况。换句话说。外部联接的语法不可靠。使用隐式联接没有任何借口,使用显式联接你不会从中获得任何东西,它们可以产生更多问题。

您需要教育您的开发人员并告诉他们这段代码(自1992年以来已经过时!)不再可接受。

答案 2 :(得分:0)

这是一个快速的,但是这个,CAST('1/1 /'+ CAST(DATEPART(YEAR,E.DUR)AS CHAR)AS DATETIME),它可能导致Table2 E上的表扫描,因为该功能很可能必须针对每一行进行评估。