在 SQL Server 中,我有一个表
order_lines
,其中包含 ordered
和 served
列。
如何才能让下面的查询不扫描全表?
SELECT *
FROM order_lines
WHERE ordered - served > 0
选项 1: 为两列建立索引。这不应该起作用,因为 SQL Server 仍然需要扫描所有索引来执行减法并检查该行对于查询是否有效,对吗?
选项 2:创建一个“待处理”列和索引
选项 3:还有其他选项吗?
ordered - served > 0
通常不可进行搜索。
也不能通过将其表示为
ordered > served
来将其重新排列为可搜索。列与列的比较不可控制。
如果查找中要使用的值包含在行本身中,则无法明智地使用索引查找来查找行。
然而,ordered - served > 0
可以通过使用计算列来made 进行优化控制。
假设你原来的桌子是这样的
CREATE TABLE order_lines
(
order_line_id INT NOT NULL PRIMARY KEY,
order_id INT NOT NULL,
product_id INT NOT NULL,
/*Other columns*/
ordered INT NOT NULL,
served INT NOT NULL
)
您可以创建计算列...
ALTER TABLE order_lines ADD pending AS ordered - served;
然后索引该计算列
CREATE INDEX IX_pending ON order_lines(pending);
为了“覆盖”问题中给出的查询,索引需要一个包含表中每一列的
INCLUDE
子句,这不太可能通过此处的成本/收益分析来证明是合理的。
因此,如果查询使用上述索引,它还需要查找基表以获取丢失的列,并且只有在谓词具有相当选择性的情况下才会选择此查询计划。下面的计划中缺少索引警告是在抱怨未包含的列。
您真的需要在此处使用
*
,还是可以选择更少的列,然后将它们包含在索引中?
假设未履行的订单行仅占表格的一小部分,并且您主要对找到这些订单感兴趣,那么潜在的中间立场可能是
CREATE INDEX IX_pending ON order_lines(pending)
INCLUDE (order_line_id,order_id,product_id, ordered, served)
WHERE pending > 0;
⚠️ 但这不是有效的索引创建,因为过滤谓词不能是计算列(或像
ordered > served
这样的表达式)
索引视图可以让你做同样的事情
CREATE VIEW dbo.pending_order_lines
WITH SCHEMABINDING
AS
SELECT order_line_id, order_id, product_id, ordered, served
FROM dbo.order_lines
WHERE ordered > served;
GO
CREATE UNIQUE CLUSTERED INDEX UCIX ON dbo.pending_order_lines(order_line_id)
然后是示例用法
SELECT *
FROM dbo.pending_order_lines WITH(NOEXPAND)
根据您使用的引擎版本,可能需要也可能不需要
NOEXPAND
提示才能有效地使用索引视图。