2014-02-21 52 views
3

下面的T-SQL查詢花費54秒執行:如何提高SQL Server Select查詢的性能?

SELECT top (3) 
    a.c1, b.c2, c.c3, d.c4 
FROM 
    table1 as a WITH (NOLOCK) 
JOIN 
    table2 as b WITH (NOLOCK) ON a.c1 = b.c4 
LEFT JOIN 
    table3 as c WITH (NOLOCK) ON a.c1 = c.c4 
LEFT JOIN 
    table4 as d WITH (NOLOCK) ON b.c3 = d.c1 
WHERE 
    b.source = '8R' 
ORDER BY 
    b.RecvdDate ASC 

而同樣的查詢按降序內的第二

SELECT top (3) 
    a.c1, b.c2, c.c3, d.c4 
FROM 
    table1 as a WITH (NOLOCK) 
JOIN 
    table2 as b WITH (NOLOCK) ON a.c1 = b.c4 
LEFT JOIN 
    table3 as c WITH (NOLOCK) ON a.c1 = c.c4 
LEFT JOIN 
    table4 as d WITH (NOLOCK) ON b.c3 = d.c1 
WHERE 
    b.source = '8R' 
ORDER BY 
    b.RecvdDate DESC 

順序執行排序所以,我怎麼能提高的性能查詢這兩個排序順序?

我使用Microsoft SQL Server 2012(SP1) - 11.0.3128.0(X64),標準版(64位)在Windows NT 6.2(生成9200:)使用SET STATISTICS PROFILE ON

執行計劃如下:

Rows     Executes    StmtText                                                               StmtId  NodeId  Parent  PhysicalOp      LogicalOp      Argument                                                               DefinedValues                   EstimateRows EstimateIO EstimateCPU AvgRowSize TotalSubtreeCost OutputList                              Warnings      Type                Parallel EstimateExecutions 
-------------------- -------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ----------- ----------- ----------- ------------------------------ ------------------------------ ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------- ------------- ------------- ------------- ----------- ---------------- -------------------------------------------------------------------------------------------------------------------------------- ------------------------------- ---------------------------------------------------------------- -------- ------------------ 
3     1     SELECT top 3 a.c1, b.c2, c.c3, d.c4 
FROM table1 as a WITH (NOLOCK) JOIN table2 as b WITH (NOLOCK) ON a.c1 = b.c1 LEFT JOIN table3 as c WITH (NOLOCK) ON 1   1   0   NULL       NULL       NULL                                                                NULL                     3    NULL   NULL   NULL  0.1093194  NULL                                NULL       SELECT               0  NULL 
3     1      |--Top(TOP EXPRESSION:((3)))                                                         1   2   1   Top       Top       TOP EXPRESSION:((3))                                                            NULL                     3    0    3E-07   93   0.1093194  [a].[c1], [table2].[c2], [c].[c3], [d].[c4]              NULL       PLAN_ROW               0  1 
3     1       |--Nested Loops(Left Outer Join, WHERE:([DB].[dbo].[table3].[c3] as [table3].[c3]=[DB].[dbo].[table4].[c1] as [d].[c1]))                    1   3   2   Nested Loops     Left Outer Join    WHERE:([DB].[dbo].[table2].[c3] as [table2].[c3]=[DB].[dbo].[table4].[id] as [d].[id])                               NULL                     3    0    221.8893  101   0.1093191  [a].[c1], [table2].[c2], [table2].[RecvdDate], [c].[c3], [d].[c4]    NULL       PLAN_ROW               0  1 
3     1        |--Nested Loops(Left Outer Join, OUTER REFERENCES:([a].[c1], [Expr1012]) WITH ORDERED PREFETCH)                                   1   4   3   Nested Loops     Left Outer Join    OUTER REFERENCES:([a].[c1], [Expr1012]) WITH ORDERED PREFETCH                                              NULL                     3    0    18.49077  99   0.1057252  [a].[c1], [table2].[c2], [table2].[RecvdDate], [table2].[C3], [c].[c3] NULL       PLAN_ROW               0  1 
3     1        | |--Nested Loops(Inner Join, OUTER REFERENCES:([table2].[c4], [Expr1011]) WITH ORDERED PREFETCH)                                 1   6   4   Nested Loops     Inner Join      OUTER REFERENCES:([table2].[c4], [Expr1011]) WITH ORDERED PREFETCH                                            NULL                     3    0    18.78465  31   0.09258068  [a].[c1], [table2].[c2], [table2].[RecvdDate], [table2].[C3]    NULL       PLAN_ROW               0  1 
27     1        | | |--Nested Loops(Inner Join, OUTER REFERENCES:([table2].[c1], [Expr1010]) WITH ORDERED PREFETCH)                               1   8   6   Nested Loops     Inner Join      OUTER REFERENCES:([table2].[c1], [Expr1010]) WITH ORDERED PREFETCH                                            NULL                     22.09678  0    136.1955  41   0.07926979  [table2].[c4], [table2].[c2], [table2].[RecvdDate], [table2].[C3]  NULL       PLAN_ROW               0  1 
19928681    1        | | | |--Index Scan(OBJECT:([DB].[dbo].[table2].[IX_datereceived] AS [table2]), ORDERED BACKWARD)                          1   10   8   Index Scan      Index Scan      OBJECT:([DB].[dbo].[table2].[IX_datereceived] AS [table2]), ORDERED BACKWARD                                    [table2].[c1], [table2].[RecvdDate]     22.09678  66.78609  35.84109  19   0.003349548  [table2].[c1], [table2].[RecvdDate]                NULL       PLAN_ROW               0  1 
27     19928681       | | | |--Clustered Index Seek(OBJECT:([DB].[dbo].[table2].[PK_c1] AS [table2]), SEEK:([table2].[c1]=[DB].[dbo].[table2].[c1] as [table2].[c1]), 1   12   8   Clustered Index Seek   Clustered Index Seek   OBJECT:([DB].[dbo].[table2].[PK_c1] AS [table2]), SEEK:([table2].[c1]=[DB].[dbo].[table2].[c1] as [table2].[c1]), WHERE:([DB].[dbo].[table2].[Source] [table2].[c4], [table2].[c2], [table2].[C3] 3.047679  0.003125  0.0001581  77   0.07582787  [table2].[c4], [table2].[c2], [table2].[C3]            NULL       PLAN_ROW               0  23.09678 
3     3        | | |--Index Seek(OBJECT:([DB].[dbo].[table1].[PK_c1] AS [a]), SEEK:([a].[c1]=[DB].[dbo].[table2].[c4] as [table2].[c4]) ORDERED FORWARD)         1   20   6   Index Seek      Index Seek      OBJECT:([DB].[dbo].[table1].[PK_c1] AS [a]), SEEK:([a].[c1]=[DB].[dbo].[table2].[c4] as [table2].[c4]) ORDERED FORWARD                  [a].[c1]                 1    0.003125  0.0001581  11   0.02297952  [a].[c1]                            NULL       PLAN_ROW               0  7.000085 
3     3        | |--Clustered Index Seek(OBJECT:([DB].[dbo].[table3].[table3_PK] AS [c]), SEEK:([c].[c4]=[DB].[dbo].[table1].[c1] as [a].[c1]) ORDERED FORWARD)         1   21   4   Clustered Index Seek   Clustered Index Seek   OBJECT:([DB].[dbo].[table3].[table3_PK] AS [c]), SEEK:([c].[c4]=[DB].[dbo].[table1].[c1] as [a].[c1]) ORDERED FORWARD                    [c].[c3]                   1    0.003125  0.0001581  75   0.01313197  [c].[c3]                              NULL       PLAN_ROW               0  4 
36     3        |--Table Scan(OBJECT:([DB].[dbo].[table4] AS [d]))                                             1   22   3   Table Scan      Table Scan      OBJECT:([DB].[dbo].[table4] AS [d])                                                    [d].[id], [d].[c4]               12   0.0032035  9.17E-05  17   0.0035703  [d].[id], [d].[c4]                          NO STATS:([table4].[c1]) PLAN_ROW               0  3.999999 

(11 row(s) affected) 

Link to execution plan in xml format:

+3

我們需要查看查詢計劃(實際的QP比估計的QP要好)將它們另存爲* .SQLPLAN文件到一些可以訪問因特網的存儲中,然後在這裏添加鏈接。 – RBarryYoung

+0

和表的定義,包括所有可用的索引。加上數據行爲的描述(如實體關係圖中所示)。還有其他的東西你可以給。 – MatBailie

+0

如果您只選擇前3行,是否可以添加另一個'where'條件來限制'RecvdDate'到最後5天?這會丟棄大部分不需要的行。 –

回答

2

table2有32,582,700行。

估計的計劃如下所示。

enter image description here

RecvdDate有一個非覆蓋索引和計劃有重點查找能夠恢復丟失的列和source = '8R'計算謂詞。

SQL Server估計在找到TOP 3匹配行之前,它需要做22-23次這樣的查找,並且它可以退出。

這假定匹配8R謂詞的行相對於日期是均勻分佈的。在你的情況下,他們不是,他們都在以後的日期。它實際上正在做19,928,681個實際的查詢(來自STATISTICS PROFILE的輸出),而不是估計的20個左右。

修復它的最簡單方法是提供一個source, RecvdDate索引。就這個查詢而言,它與哪個方向無關。四種可能性中的任何一種都可行。

source asc, RecvdDate asc 
source asc, RecvdDate desc 
source desc, RecvdDate asc 
source desc, RecvdDate desc 

它仍然可以做一個平等尋求source和需要得到RecvdDate ASCRecvdDate DESC向前或向後遍歷匹配的行。

+0

我按照你的建議提供了一個索引,它幫助我解決了這個問題。非常感謝你.. :) – Leejoy

0

是性能一致 ?與大不同我的猜測是,你有

source, RecvdDate DESC 

一個綜合指數,這意味着通過RecvdDate升序排列查詢時不能使用。

可以添加單獨的指數sourceRecvdDate這將提高性能(與單個列索引的順序並不重要),或在上升爲了增加與RecvdDate另一個綜合指數。

+0

找到了驗證這個理論的問題。 http://stackoverflow.com/questions/743858/sql-server-indexes-ascending-or-descending-what-difference-does-it-make – TTeeple

+0

是的表現是一致的。 – Leejoy

+0

@Leejoy你有沒有類似於我所設想的複合指數? –