【发布时间】:2011-11-20 20:41:20
【问题描述】:
我们发现这些查询之间存在巨大差异。
慢查询
SELECT MIN(col) AS Firstdate, MAX(col) AS Lastdate
FROM table WHERE status = 'OK' AND fk = 4193
表'表'。扫描计数 2,逻辑读取 2458969,物理读取 0,预读读取 0,lob 逻辑读取 0,lob 物理读取 0,lob 预读读取 0。
SQL Server 执行时间:CPU 时间 = 1966 毫秒,运行时间 = 1955 毫秒。
快速查询
SELECT count(*), MIN(col) AS Firstdate, MAX(col) AS Lastdate
FROM table WHERE status = 'OK' AND fk = 4193
表'表'。扫描计数 1,逻辑读取 5803,物理读取 0,预读读取 0,lob 逻辑读取 0,lob 物理读取 0,lob 预读读取 0。
SQL Server 执行时间:CPU 时间 = 0 毫秒,运行时间 = 9 毫秒。
问题
查询之间的巨大性能差异是什么原因?
更新 基于作为 cmets 给出的问题的一点更新:
执行顺序或重复执行不会改变性能。 没有使用额外的参数,并且(测试)数据库在执行期间没有做任何其他事情。
慢查询
|--Nested Loops(Inner Join)
|--Stream Aggregate(DEFINE:([Expr1003]=MIN([DBTest].[dbo].[table].[startdate])))
| |--Top(TOP EXPRESSION:((1)))
| |--Nested Loops(Inner Join, OUTER REFERENCES:([DBTest].[dbo].[table].[id], [Expr1008]) WITH ORDERED PREFETCH)
| |--Index Scan(OBJECT:([DBTest].[dbo].[table].[startdate]), ORDERED FORWARD)
| |--Clustered Index Seek(OBJECT:([DBTest].[dbo].[table].[PK_table]), SEEK:([DBTest].[dbo].[table].[id]=[DBTest].[dbo].[table].[id]), WHERE:([DBTest].[dbo].[table].[FK]=(5806) AND [DBTest].[dbo].[table].[status]<>'A') LOOKUP ORDERED FORWARD)
|--Stream Aggregate(DEFINE:([Expr1004]=MAX([DBTest].[dbo].[table].[startdate])))
|--Top(TOP EXPRESSION:((1)))
|--Nested Loops(Inner Join, OUTER REFERENCES:([DBTest].[dbo].[table].[id], [Expr1009]) WITH ORDERED PREFETCH)
|--Index Scan(OBJECT:([DBTest].[dbo].[table].[startdate]), ORDERED BACKWARD)
|--Clustered Index Seek(OBJECT:([DBTest].[dbo].[table].[PK_table]), SEEK:([DBTest].[dbo].[table].[id]=[DBTest].[dbo].[table].[id]), WHERE:([DBTest].[dbo].[table].[FK]=(5806) AND [DBTest].[dbo].[table].[status]<>'A') LOOKUP ORDERED FORWARD)
快速查询
|--Compute Scalar(DEFINE:([Expr1003]=CONVERT_IMPLICIT(int,[Expr1012],0)))
|--Stream Aggregate(DEFINE:([Expr1012]=Count(*), [Expr1004]=MIN([DBTest].[dbo].[table].[startdate]), [Expr1005]=MAX([DBTest].[dbo].[table].[startdate])))
|--Nested Loops(Inner Join, OUTER REFERENCES:([DBTest].[dbo].[table].[id], [Expr1011]) WITH UNORDERED PREFETCH)
|--Index Seek(OBJECT:([DBTest].[dbo].[table].[FK]), SEEK:([DBTest].[dbo].[table].[FK]=(5806)) ORDERED FORWARD)
|--Clustered Index Seek(OBJECT:([DBTest].[dbo].[table].[PK_table]), SEEK:([DBTest].[dbo].[table].[id]=[DBTest].[dbo].[table].[id]), WHERE:([DBTest].[dbo].[table].[status]<'A' OR [DBTest].[dbo].[table].[status]>'A') LOOKUP ORDERED FORWARD)
回答
Martin Smith 下面给出的答案似乎可以解释这个问题。超短版本是 MS-SQL 查询分析器在慢速查询中错误地使用了查询计划,从而导致完整的表扫描。
在 startdate、FK 和 status 列上添加 Count(*)、带有 (FORCESCAN) 的查询提示或组合索引可修复性能问题。
【问题讨论】:
-
如果在第二个查询之后再次运行第一个查询会怎样?
-
可能是因为当您使用 count(*) 时,您不会检查每条记录的 fk=4193?
-
您是在一个接一个地运行这些吗?如果是这样:如果您将
DBCC DROPCLEANBUFFERS和DBCC FREEPROCCACHE放在两个查询之前会发生什么?如果您更改顺序 - 先运行快速查询,然后运行慢速查询,会发生什么? -
@Martin Smith:我在想 1. 统计数据更新 2. 可重复性
-
您的计划与查询不匹配。 -1 误导我们。
标签: sql sql-server performance statistics correlation