任何人都可以解释为什么在使用SQL Azure时,下面的第一个查询需要四分钟,但第二个查询只需要两秒钟?唯一的区别是"订单"第一行中的前缀。
select top 1 orders.*
from (
select oi.OrderItemID, o.*
from OrderItem oi
inner join [Order] o on oi.OrderID = o.OrderID
where o.OrderStatusID = 1
) orders
left join GoalProcessingStatus gps on (gps.GoalID = 74 and gps.OrderItemID =
orders.OrderItemID)
where orders.AccountID = 4
and orders.WhenCreated >= @FromDate
and orders.WhenCreated < @UntilDate
and (gps.GoalProcessingStatusID is null or ( gps.Attempts < 10 and gps.IsProcessed <> 1))
order by orders.WhenCreated
select top 1 *
from (
select oi.OrderItemID, o.*
from OrderItem oi
inner join [Order] o on oi.OrderID = o.OrderID
where o.OrderStatusID = 1
) orders
left join GoalProcessingStatus gps on (gps.GoalID = 74 and gps.OrderItemID =
orders.OrderItemID)
where orders.AccountID = 4
and orders.WhenCreated >= @FromDate
and orders.WhenCreated < @UntilDate
and (gps.GoalProcessingStatusID is null or ( gps.Attempts < 10 and gps.IsProcessed <> 1))
order by orders.WhenCreated
好的,所以它变得更奇怪了。上面仍然有效,但如果我采用慢查询并注释掉行 orders.WhenCreated&gt; = @FromDate 行,则时间下降到2秒(FYI WhenCreated的类型为datetime和@FromDate是一个日期时间变量):
select top 1 orders.*
from (
select oi.OrderItemID, o.*
from OrderItem oi
inner join [Order] o on oi.OrderID = o.OrderID
where o.OrderStatusID = 1
) orders
left join GoalProcessingStatus gps on (gps.GoalID = 74 and gps.OrderItemID =
orders.OrderItemID)
where orders.AccountID = 4
-- REMOVING THE LINE BELOW WILL SPEED UP THE QUERY TO ABOUT 2 SECONDS
-- and orders.WhenCreated >= @FromDate
and orders.WhenCreated < @UntilDate
and (gps.GoalProcessingStatusID is null or ( gps.Attempts < 10 and gps.IsProcessed <> 1))
order by orders.WhenCreated
更奇怪的是,如果我在其下方注释 @UntilDate 比较,那么不适用相同的性能增益 - 只有在我删除@FromDate比较时才会有所不同
以下是要求的统计数据:
(1行(s)受影响) 表&#39; GoalProcessingStatus&#39;。扫描计数12486,逻辑读取811590,物理读取0,预读取读取0,lob逻辑读取0,lob物理读取0,lob预读读取0。 表&#39; OrderItem&#39;。扫描计数9206,逻辑读取29452,物理读取0,预读取读取0,lob逻辑读取0,lob物理读取0,lob预读读取0。 表&#39;订单&#39;。扫描计数1,逻辑读取48756,物理读取0,预读读取0,lob逻辑读取0,lob物理读取0,lob预读读取0。
(1行受影响)
SQL Server执行时间: CPU时间= 796 ms,经过时间= 430468 ms。
SQL Server执行时间: CPU时间= 0 ms,经过时间= 0 ms。
(1行(s)受影响) 表&#39; GoalProcessingStatus&#39;。扫描计数0,逻辑读取75714,物理读取0,预读取读取0,lob逻辑读取0,lob物理读取0,lob预读读取0。 表&#39; OrderItem&#39;。扫描计数9207,逻辑读取29455,物理读取0,预读取读取0,lob逻辑读取0,lob物理读取0,lob预读读取0。 表&#39;订单&#39;。扫描计数1,逻辑读取48759,物理读取0,预读读取0,lob逻辑读取0,lob物理读取0,lob预读读取0。
(1行受影响)
SQL Server执行时间: CPU时间= 0 ms,经过时间= 1024 ms。 SQL Server解析和编译时间: CPU时间= 0 ms,经过时间= 0 ms。
SQL Server执行时间: CPU时间= 0 ms,经过时间= 0 ms。
看起来有一个关于GoalProcessingStatus的扫描,虽然我无法猜测为什么它只在前一个场景中被激活。
我被问到了两个主要指数:
CREATE NONCLUSTERED INDEX [nci_wi_GoalProcessingStatus_1DE49F3EF3D056EFB506085E35F68FFE] ON [dbo].[GoalProcessingStatus]
(
[GoalID] ASC
)
INCLUDE ( [Attempts],
[IsProcessed],
[OrderItemID]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
GO
第二个索引(在更快的查询中使用)只是GoalProcessingStatus表的主键。
有趣的是,我没有创建第一个查询。它由Azure的索引服务自动完成。它实际上是一个有效且有用的索引,但显然与此查询无关。有趣的是,SQL选择使用它。
答案 0 :(得分:1)
感谢您发布STATISTICS IO和执行计划。请发布与这些表关联的各种索引和架构。
在仅选择orders。*数据时,SQL Server查询优化器决定使用“GoalProcessingStatus.nci_wi_Goal ...”索引。该索引包含您在谓词中引用的每个GoalProcessingStatus列。
在选择*数据时,SQL Server查询优化器决定使用“IX_U_GoalP ...”索引并对聚簇索引进行后续查找。这是因为它需要GoalProcessingStatus表中的所有列。
要继续解决这个问题,你需要弄清楚为什么索引“GoalProcessingStatus.nci_wi_Goal ...”的表现如此糟糕。没有索引和模式定义,我很难提供帮助。此外,XML执行计划还将提供更多信息。
在重新访问查询“order。*”查询后,谓词中引用的唯一列是GoalProcessingStatusID,Attempts和IsProcessed。您的非聚集索引可能缺乏唯一性。
答案 1 :(得分:0)
好奇,你能不能将Orders的逻辑移到第一部分来限制初始记录集的大小?
可能发生的两件事
1:错误的查询计划。如果您在参数@FromDate和@untildate中对您使用的值进行硬编码,您会得到相同的结果吗?如果它运行得很快,你可能会因为参数嗅探而得到错误的查询计划。
2 :(不太可能)我从你的QP中看到你正在为GoalProcessingStatus使用2个不同的索引(一个在快速计划中,一个在慢速计划中)。如果你看一下IX_U_Goal ...和nci_wi_goal的索引定义......它可能会让你深入了解它与另一个相比需要更长的时间。
我相信如果你将where子句中的order逻辑移动到你的第一个子查询中,它在两种情况下应该更快。