选择TOP(n)的不同SQL查询计划

时间:2013-04-15 11:24:23

标签: sql-server-2008

我正在尝试查看简单选择Top(n)的查询计划。每次我更改n(我得到的记录数)时,查询计划都会发生变化,其中Select Top 10会导致性能问题,少于10次或大于10次,查询会顺利运行。

如果实体框架(4.2)有所不同,则会生成查询。

查询是:

 exec sp_executesql N'SELECT TOP (10) 
[Project1].[Id] AS [Id], 
[Project1].[DateReceived] AS [DateReceived], 
[Project1].[Status] AS [Status], 
[Project1].[Subject] AS [Subject], 
[Project1].[Description] AS [Description], 
[Project1].[Path] AS [Path], 
[Project1].[C1] AS [C1], 
[Project1].[C2] AS [C2], 
[Project1].[C3] AS [C3],
.
.
.
.
.
.
.

WHERE [Project1].[row_number] > 0
ORDER BY [Project1].[DateReceived] DESC',N'@p__linq__0 int,@p__linq__1 int,@p__linq__2 datetime2(7),@p__linq__3 datetime2(7),@p__linq__4 nvarchar(4000),@p__linq__5 nvarchar(4000),@p__linq__6 nvarchar(4000),@p__linq__7 nvarchar(4000)',@p__linq__0=-1,@p__linq__1=-1,@p__linq__2='2013-03-15 00:00:00',@p__linq__3='2013-04-15 23:59:55',@p__linq__4=N'ALL',@p__linq__5=N'ALL',@p__linq__6=N'',@p__linq__7=N'%%'

为什么TOP 10特别导致性能问题?

我无法分享图片,这里是链接:

http://imageshack.us/photo/my-images/407/top10a.png/

http://imageshack.us/photo/my-images/580/top20x.png/

1 个答案:

答案 0 :(得分:0)

正如@JanDrozen所说,它最有可能出现统计问题。当数据大小超过某个阈值时,生成的执行计划不再是最佳计划,但统计信息不允许它获得正确的估计行数。优化器并不总是生成最佳执行计划。这是一项令人印象深刻的编程成就,通常会从我们的谷壳中获得金币,但它实际上只能利用它手头的数据做到最好。它使用肉体统计数据,并使用估计的结果集大小来确定它认为最佳计划。

在没有尝试首先更新统计信息的情况下判断是否是统计信息问题的一种方法是启用实际执行计划,并查看属性。

检查:

  • 如果数据进入管道,估计的行数接近实际行数。
  • 执行计划的属性表明优化程序已达到最佳计划。在属性中,它会告诉您选择该计划的原因。有时,如果统计数据已过时,优化程序永远不会找到最佳计划,只需使用它能找到的最佳计划。

此查询是更新示例adventureworks数据库中的统计信息的示例。

USE AdventureWorks2012;
GO
UPDATE STATISTICS Production.Product(Products)
    WITH FULLSCAN, NORECOMPUTE;
GO

存储过程sp_updatestats [ [ @resample = ] 'resample'] 但我从来没有取得过很好的成绩,我永远不会强迫它用全扫描进行更新,这在我的经验中是获得良好统计数据的最佳方式。

如果你需要为大量的表执行此操作,这里是一个我以前使用动态sql重新生成统计信息的脚本。

DECLARE @sql nvarchar(MAX);
SELECT @sql = (SELECT 'UPDATE STATISTICS ' +
                  quotename(s.name) + '.' + quotename(o.name) +
                  ' WITH FULLSCAN; ' AS [text()]
           FROM   sys.objects o
           JOIN   sys.schemas s ON o.schema_id = s.schema_id
           WHERE  o.type = 'U'
           FOR XML PATH(''), TYPE).value('.', 'nvarchar(MAX)');
PRINT @sql
EXEC (@sql)

Here是一篇关于统计数据的好文章,可以很好地分析它们是什么,它们做了什么,以及如何看待它们。