如何解决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
数据类型:
我在 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 举报,一经查实,本站将立刻删除。