为什么此声明显示索引在Exec计划中扫描?

时间:2013-05-30 01:33:20

标签: sql database-administration query-performance database-tuning

我有两个语句返回相同的结果,但产生不同的执行计划。

  • 首先>>>索引寻求
  • 第二个>>>索引扫描

任何人都可以解释原因吗?

实施例

CREATE TABLE OrderDetails (intOrderId int, intItemId int, dtOrderDate Datetime, intQty int, intPrice int, intDiscount int)
GO

CREATE CLUSTERED INDEX CI_OrderId ON OrderDetails(intOrderId)
GO

CREATE NONCLUSTERED INDEX NCI_ItemId ON OrderDetails(intItemId)
GO

-- Populate Data
SET NOCOUNT ON

DECLARE @i int
SET @i =10
WHILE @i < 100000
BEGIN
     INSERT INTO OrderDetails
     VALUES (@i, round(rand()*9999,0)+1, getdate() - round(rand()*999,0), round(rand()*99,0)+1, round(rand()*9999,0)+1, round(rand()*99,0)+1)

     SET @i = @i + 1
END
GO

-- Check Execution Plans

-- NCI SEEK
SELECT intOrderId, intItemId 
FROM   OrderDetails
WHERE  intItemId = 600 * 10

-- NCI SCAN
SELECT intOrderId, intItemId 
FROM   OrderDetails
WHERE  intItemId/10 = 600

1 个答案:

答案 0 :(得分:2)

有两个原因......

  1. 因为SQL Server不能用代数方式操作WHERE子句。
  2. 因为有10个值与您的第二个查询匹配
  3. 第一条评论的含义是,优化工具可以看到您正在对intItemId执行某些操作,但它不会尝试找到快捷方式。相反,它必须在每一行上执行/10以查看结果。

    (它不知道6000/10 = 600但是5999没有。所以它会在每一行上尝试。)

    这与第二个原因有关。您的问题意味着您希望第二个查询只返回行intItemId = 6000。但由于整数运算,6001/106009/10都等于600。因此,当您进行整数运算时,x/10=y变为x=y*10的代数操作无效。这是优化者不尝试的部分原因。


    简而言之:每当您以虚拟 任何 方式操作索引字段时,您将阻止使用索引并获取扫描而不是搜索。 / p>