0

我的数据库存储在 sql server 2005 db 中。

此查询执行时间不到一秒:

SELECT * FROM ( 

SELECT  ROW_NUMBER() OVER ( ORDER BY tblOrders.orderid ) AS RowNum,   
SUM(tblProducts.Price) as price
FROM tblOrders 
LEFT OUTER JOIN tblOrderDetails ON tblOrders.orderid = tblOrderDetails.OrderId 
LEFT OUTER JOIN tblProducts ON tblOrderDetails.ProductId = tblProducts.ProductId
GROUP BY tblOrders.orderid

) as x
where RowNum >=  21001 and RowNum <  21011

虽然此查询需要 10 秒才能执行:

SELECT * FROM ( 

SELECT  ROW_NUMBER() OVER ( ORDER BY tblOrders.orderid ) AS RowNum,   
SUM(tblProducts.Price) as price, 
OrderDate
FROM tblOrders 
LEFT OUTER JOIN tblOrderDetails ON tblOrders.orderid = tblOrderDetails.OrderId 
LEFT OUTER JOIN tblProducts ON tblOrderDetails.ProductId = tblProducts.ProductId
GROUP BY tblOrders.orderid, tblOrders.OrderDate

) as x
where RowNum >=  21001 and RowNum <  21011

为什么会有这样的差异?

所有表都有一个名为 id 的列,其中包含主键。不知道为什么 orderid 和 ProductId 也存在,因为我没有设计数据库。

/巴里

更新

OrderDate 是日期时间

第二次更新

请记住,三个表都有一个 id 列作为主键。但是,在表之间引用时会使用 orderid、productid 等。我不确定为什么要以这种方式实施,但我猜它非常错误。

tblOrders:
Id; int; no null; PK
OrderId; int; allow null
OrderDate; datetime; allow null

tblOrderDetails:
Id; int; no null; PK
OrderId; int; allow null
ProductId; int; allow null

tblProducts:
Id; int; PK; no null
ProductId; allow null
Price; money; allow null

这是一个足够的查询执行计划吗? -

在此处输入图像描述

第三次更新

这只需一秒钟即可执行 -

SELECT  ROW_NUMBER() OVER ( ORDER BY tblOrders.orderid ) AS RowNum,   
SUM(tblProducts.Price) as price, 
OrderDate
FROM tblOrders 
LEFT OUTER JOIN tblOrderDetails ON tblOrders.orderid = tblOrderDetails.OrderId 
LEFT OUTER JOIN tblProducts ON tblOrderDetails.ProductId = tblProducts.ProductId
GROUP BY tblOrders.orderid, OrderDate

而这只有 2 秒 -

SELECT * FROM (
  SELECT  ROW_NUMBER() OVER ( ORDER BY tblOrders.orderid ) AS RowNum,
  SUM(tblProducts.Price) as price,
  MAX(tblOrders.OrderDate) as OrderDate  -- do this instead of grouping
FROM tblOrders
  LEFT OUTER JOIN tblOrderDetails ON tblOrders.orderid = tblOrderDetails.OrderId
  LEFT OUTER JOIN tblProducts ON tblOrderDetails.ProductId = tblProducts.ProductId
GROUP BY tblOrders.orderid  ) as x

但这需要10秒——

SELECT * FROM (
  SELECT  ROW_NUMBER() OVER ( ORDER BY tblOrders.orderid ) AS RowNum,
  SUM(tblProducts.Price) as price,
  MAX(tblOrders.OrderDate) as OrderDate  -- do this instead of grouping
FROM tblOrders
  LEFT OUTER JOIN tblOrderDetails ON tblOrders.orderid = tblOrderDetails.OrderId
  LEFT OUTER JOIN tblProducts ON tblOrderDetails.ProductId = tblProducts.ProductId
GROUP BY tblOrders.orderid  ) as x
where RowNum >=  21001 and RowNum <  21011

where 子句增加了 8 秒。为什么?

4

4 回答 4

2

我敢打赌,在输出列表和分组子句中都包含“tblOrders.OrderDate”的甜甜圈会导致您的速度变慢。我建议你SET STATISTICS IO ON运行这两个查询,看看你如何在每个表上获得不同的扫描和搜索。

SQL 引擎很可能对考虑 OrderDate 列的第二个查询有一个截然不同的计划,从而导致更多的 CPU 处理或(更有可能)更多的磁盘 IO。

于 2012-04-15T21:26:23.943 回答
0

如果没有实际的表结构和执行计划,我无法准确回答,但如果 orderid 在 tblOrders 中是唯一的,那么最好从 group by 语句中删除 OrderDate 并在选择列表中将其添加为min(tblOrders.OrderDate) as OrderDate. 它应该给出相同的结果(如果 tblOrders.orderid 是唯一键)但工作得更好。

于 2012-04-16T09:36:26.383 回答
0

没有执行计划就无法回答这个问题,但我可以猜测:

  • 附加列可能会阻止使用索引
  • 慢查询的基数很高
  • OrderDate 的统计信息不知何故已过时 (exec sp_updatestats)

更新:您发布的执行计划确实很可怕。

创建索引:

create unique nonclustered index x0 on tblOrder(orderid) include (OrderDate)
create unique nonclustered index x1 on tblProduct (productid) include (Price)
create nonclustered index x2 on tblOrderDetails(orderid, ProductId)
于 2012-04-15T21:11:48.927 回答
0

什么是订单日期?约会时间?虽然这些查询看起来非常相似,但我怀疑 OrderDate 包含时间信息,因此排序和分组要昂贵得多(并导致第二个查询的子查询中有更多行)。

考虑以下更改:

SELECT RowNum, price, DD = DATEADD(DAY, DD, '19000101') FROM (     
SELECT  ROW_NUMBER() OVER ( ORDER BY tblOrders.orderid ) AS RowNum,   
SUM(tblProducts.Price) as price, 
DATEDIFF(DAY, '19000101', tblOrders.OrderDate) as DD
FROM tblOrders 
LEFT OUTER JOIN tblOrderDetails ON tblOrders.orderid = tblOrderDetails.OrderId 
LEFT OUTER JOIN tblProducts ON tblOrderDetails.ProductId = tblProducts.ProductId
GROUP BY tblOrders.orderid, DATEDIFF(DAY, '19000101', tblOrders.OrderDate)

) as x
where RowNum >=  21001 and RowNum <  21011
ORDER BY RowNum;

在 SQL Server 2008 或更高版本中,您可以将其简化为CONVERT(DATE, OrderDate)...

于 2012-04-15T23:04:42.760 回答