【问题标题】:How to improve the performance of a SQL Server Select query?如何提高 SQL Server Select 查询的性能?
【发布时间】:2014-03-23 05:49:22
【问题描述】:

执行以下 T-SQL 查询需要 54 秒:

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

那么我怎样才能提高这两种排序顺序的查询性能呢?

我在 Windows NT 6.2(内部版本 9200:)上使用 Microsoft SQL Server 2012 (SP1) - 11.0.3128.0 (X64) 标准版(64 位)

使用 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:

【问题讨论】:

  • 我们需要查看查询计划(实际的 QP 比估计的 QP 好)将它们保存为 *.SQLPLAN 文件到一些互联网可访问的存储中,然后在此处添加指向它们的链接。
  • 和表定义,包括所有可用的索引。加上对数据行为的描述(如实体关系图中所示)。以及您可以给予的任何其他东西。
  • 如果您只选择前 3 行,您能否添加另一个 where 条件以将 RecvdDate 限制为过去 5 天?这将丢弃您不需要的大部分行。

标签: sql sql-server database sql-server-2012 rdbms


【解决方案1】:

这种表现一致吗?有了这么大的不同,我的猜测是您在

上有一个复合索引
source, RecvdDate DESC

表示按RecvdDate升序查询时不能使用。

可以sourceRecvdDate 添加单独的索引,这将提高性能(使用单列索引,顺序无关紧要),或者使用 RecvdDate 添加另一个复合索引升序

【讨论】:

  • 发现了这个问题来验证这个理论。 stackoverflow.com/questions/743858/…
  • @Leejoy 你有一个类似于我假设的复合索引吗?
  • 这有点猜想!同样可能是所有匹配source = '8R' 的行都恰好有更晚的日期。
  • 其实我根本看不到这个。可以向前或向后扫描 source 上的相等搜索。
  • @Leejoy - 如果您想要猜测以外的任何内容,请发布执行计划。
【解决方案2】:

table2 有 32,582,700 行。

预计的计划如下。

您在RecvdDate 上有一个非覆盖索引,并且该计划有键查找来检索丢失的列并评估source = '8R' 上的谓词。

SQL Server 估计它需要执行 22 -23 次这样的查找才能找到 TOP 3 匹配的行并退出。

这假设匹配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

【讨论】:

  • 我已经按照您的建议提供了一个索引,它帮助我解决了这个问题。非常感谢.. :)
猜你喜欢
  • 2013-07-06
  • 1970-01-01
  • 1970-01-01
  • 2022-01-09
  • 1970-01-01
  • 2011-03-03
  • 2019-03-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多