【发布时间】:2023-03-05 23:30:02
【问题描述】:
这个查询大约需要01:30 来运行:
select DATEADD(dd, 0, DATEDIFF(dd, 0, t1.[OccurredOn]))
, count(t2.UserId)
, count(*) - count(t2.UserId)
from Events t1
left join (select c.UserId, min(c.OccurredOn) FirstOccurred
from Events c
where [OccurredOn] between @start and @end
group by c.UserId) t2 on t1.OccurredOn = t2.FirstOccurred and t1.UserId = t2.UserId
where t1.EventType = @eventType
and t1.[OccurredOn] between @start and @end
group by DATEADD(dd, 0, DATEDIFF(dd, 0, t1.[OccurredOn]))
order by DATEADD(dd, 0, DATEDIFF(dd, 0, t1.[OccurredOn]))
如果我从子查询中删除 WHERE 子句,它会立即运行。
单独运行子查询,WHERE 需要
如果我首先将子查询SELECT 放入表变量中,然后加入该变量,则整个查询将在 19 秒内运行。
Events 表如下所示:
[Events](
[EventType] [uniqueidentifier] NOT NULL,
[UserId] [uniqueidentifier] NOT NULL,
[OccurredOn] [datetime] NOT NULL,
)
我有以下primary, nonclustered, nounique 索引:
- 事件类型
- 用户ID
- 发生时间
这是执行计划
我使用的是 SQL Server 2008。
两件事:
- 发生了什么让这变慢了?
- 如何加快速度?
【问题讨论】:
-
请SHOW US表结构,列和它们的数据类型,告诉我们你有什么索引...... - 还有什么VERSION的SQL Server你在用吗?
-
好点,意味着添加添加。待机
-
你看过执行计划了吗?它显示了什么?
-
您确定您的查询有效吗?您的子查询返回一个名为
FirstOccured的列,这在技术上是一个谎言,因为where 子句意味着它是@start之后的第一个。此外,人们会期望 FirstOccurred 是事件的第一次发生。但事实并非如此。所以,如果你的子查询已经误导了它应该做什么 - 你怎么能确定其余的都是正确的?也许最好解释一下查询应该做什么 - 我怀疑完全重写是为了,而不仅仅是一些优化。 -
我告诉过您,您在编写查询时遇到了一些严重的问题。我还可以告诉您,您几乎肯定有错误的索引,因为您对索引的解释没有任何意义(不唯一的主索引??多个主索引??)。关键是,如果您懒得解释您的查询应该做什么 - 如何期望有人帮助您重写它并解决您的问题? - 这不是一个可以回答的问题!
标签: sql tsql optimization