微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

SQL Server - 奇怪的索引使用

如何解决SQL Server - 奇怪的索引使用

这是我正在使用的原始查询

SELECT TOP(10) * 
FROM Orders o
WHERE (o.DateAdded >= DATEADD(DAY,- 30,getutcdate())) AND (o.DateAdded <= GETUTCDATE())
ORDER BY o.DateAdded ASC,o.Price ASC
o.Quantity DESC

数据类型:

  • 添加日期 - 小日期时间
  • 价格 - 十进制(19,8)
  • 数量 - 整数

我在 Orders 表上有一个索引,其中 3 列按相同的顺序排列,所以当我运行它时,它是完美的。时间

但是,只要我将此行添加到 WHERE 子句中

AND o.Price BETWEEN convert(decimal(19,8),0) AND @BuyPrice 

一切都糟透了(不幸的是我需要那条线)。如果只是 o.Price

非常感谢有人告诉我我错过了什么。谢谢

解决方法

优化器不可能同时使用两个范围谓词。

想一想:它从索引中按 DateAdded 排序的某个位置开始扫描。它现在需要在每个单独的 DateAdded 值中寻找特定的 Price,开始扫描,并在 另一个 Price 处停止,然后跳转到下一个 { {1}}。

这叫做skip-scanning,只有在第一个谓词的值不是很多时才有效,否则效率低下,正因为如此,只有Oracle实现了它,没有SQL Server。

,

我认为这是由于 TOP 10 不能在 ORDER BY 之前发生。 而这个 ORDER BY 必须等到结果集准备好。

无需额外的价格范围,TOP 10 可以直接从现有指数中获取。但是添加第二个范围将强制首先运行另一个操作。

简而言之:

  • 首先,您的过滤器必须获取价格范围和日期范围的行。
  • 对结果集进行排序并取前 10 行。

您是否尝试在价格列中添加单独的索引?这应该会加快第一个过滤器的速度。

在很多情况下我们无法预测执行计划,但您可以尝试

  • 将按日期范围过滤的中间集写入临时表并从那里继续。您甚至可以在那里的价格列上创建索引(取决于预期的行数。可能是最佳选择)。
  • 使用 CTE 定义按日期范围过滤的集合,并使用该集合应用您的价格范围。但是 CTE 与临时表不同。最终的执行计划可能和之前一样...
  • 使用两个 CTE 定义两个集合(每个范围一个)并使用 INNER JOIN 作为与 WHERE condition1 AND condition2 相同的方法。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。