如果选择特定列,为什么我的数据库查询需要更长时间?

时间:2017-05-22 01:34:43

标签: sql sql-server

任何人都可以解释为什么在使用SQL Azure时,下面的第一个查询需要四分钟,但第二个查询只需要两秒钟?唯一的区别是"订单"第一行中的前缀。

第一次查询(4分钟)

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是一个日期时间变量):

第一次查询(4分钟)

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的扫描,虽然我无法猜测为什么它只在前一个场景中被激活。

Here is a link to the execution plan

索引

我被问到了两个主要指数:

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选择使用它。

2 个答案:

答案 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逻辑移动到你的第一个子查询中,它在两种情况下应该更快。