SQL Server:类似查询的不同执行计划和性能

Posted

技术标签:

【中文标题】SQL Server:类似查询的不同执行计划和性能【英文标题】:SQL Server : different execution plan and performance for similar queries 【发布时间】:2017-03-20 19:52:51 【问题描述】:

我在同一张表上有 2 个查询,我预计性能相似,但我仍然得到了巨大的差异 - 30 秒与 ~ 1 秒。

查询1:统计当月用户数

SELECT datepart(year,getdate()) as TheYear, 
       DATEPART(month, GETDATE()) AS TheMonth, 
       COUNT(DISTINCT Username) AS TheUsers
FROM dbo.[AP-Data] 
WHERE datepart(year,RequestDate) =  datepart(year,getdate()) 
  AND datepart(month,RequestDate) = datepart(month,getdate())

查询 2:统计本周的用户数

SELECT datepart(year,getdate()) as TheYear, 
       DATEPART(week, GETDATE()) AS TheWeek, 
       COUNT(DISTINCT Username) AS TheUsers
FROM dbo.[AP-Data] 
WHERE datepart(year,RequestDate) =  datepart(year,getdate()) 
  AND datepart(week,RequestDate) = datepart(week,getdate())

该表有大约 350 万条记录,并由 RequestDate 索引。本月的计数正在执行全表扫描,因此需要 30 秒,一周的计数在 ~ 1 秒内执行 RID 查找 - 此信息来自执行计划。

知道为什么会有差异吗?

【问题讨论】:

对某些东西是否支持 SARG 进行一些研究。如果您在 join 或 where 子句中的列上使用函数,通常无法在其上利用索引。 您根本不应该在WHERE 上使用DATEPART(something,RequestDate)。尝试重写它们以使用类似:WHERE RequestDate >= CONVERT(VARCHAR(6),GETDATE(),112) + '01' 或类似的东西 谢谢,我试过了,结果也很奇怪:'SELECT COUNT(DISTINCT Shortname) AS TheUsers FROM dbo.[AP-Data] WHERE RequestDate > '2017-03-01' 运行在一秒。但是 SELECT COUNT(DISTINCT Shortname) AS TheUsers FROM dbo.[AP-Data] WHERE RequestDate > CONCAT(datepart(year,getdate()),'-0',datepart(month,getdate()),'-01')运行时间为 30 秒。 【参考方案1】:

试试这些查询怎么样?

SELECT year(getdate()) as TheYear, month(GETDATE()) AS TheMonth,
       COUNT(DISTINCT Username) AS TheUsers
FROM dbo.[AP-Data]
WHERE RequestDate >= dateadd(month, datediff(month, 0, getdate()), 0);

和:

SELECT year(getdate()) as TheYear, month(GETDATE()) AS TheMonth,
       COUNT(DISTINCT Username) AS TheUsers
FROM dbo.[AP-Data]
WHERE RequestDate >= dateadd(week, datediff(week, 0, getdate()), 0);

在列上使用函数通常会阻止编译器使用索引。以上假设您没有未来的请求日期。

【讨论】:

它们都在 1 秒内工作。在我的初始查询中,这只是一周工作正常,我仍然有兴趣了解差异来自哪里。 同样试图获取上个月的 COUNT,但它不起作用(快):SELECT year(getdate()) as TheYear, month(GETDATE()) AS TheMonth, COUNT(DISTINCT Username) AS TheUsers FROM dbo.[AP-Data] WHERE RequestDate >= dateadd(month, datediff(month, 0, getdate())-1, 0) AND RequestDate < dateadd(month, datediff(month, 0, getdate()), 0);

以上是关于SQL Server:类似查询的不同执行计划和性能的主要内容,如果未能解决你的问题,请参考以下文章

强制SQL Server执行计划使用并行提升在复杂查询语句下的性能

sql server 执行计划(execution plan)介绍

SQL Server - 条件语句的查询执行计划

Sql Server中执行计划的缓存机制

sql server 执行计划(execution plan)介绍

Sql Server 优化 SQL 查询:如何写出高性能SQL语句