【问题标题】:Why this Statement Show Index Scan in Exec Plan?为什么此语句在执行计划中显示索引扫描?
【发布时间】:2013-05-30 01:33:19
【问题描述】:

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

  • 首先 >>> 索引搜索
  • 第二次>>>索引扫描

谁能解释一下原因?

示例

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

【问题讨论】:

  • 您能尝试重新表述这个问题吗?我真的不明白你想说什么。
  • @Mostafa - 我改写了最初的句子以澄清你的问题。如果这不是您想要的,请随时edit

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


【解决方案1】:

有两个原因...

  1. 因为 SQL Server 不会以代数方式操作您的 WHERE 子句。
  2. 因为有 10 个值与您的第二个查询匹配

我的第一条评论的意思是优化器可以看到您正在对intItemId 做某事,但它不会尝试找到捷径。相反,它必须对每一行执行/10 以查看结果。

(它不知道 6000/10 = 600,但 5999 不知道。所以它在每一行都尝试。)

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


简而言之:当您以几乎任何方式操作索引字段时,您将阻止索引的使用并获得扫描而不是搜索。

【讨论】:

  • inItemId / 10 = 600 的真正代数运算是 intItemId BETWEEN 600*10 AND 600*10+10-1,优化器不会为您做这件事。 应重新安排类似的条件,以确保不必操纵索引字段。
猜你喜欢
  • 2015-08-09
  • 2023-03-12
  • 2015-11-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-25
  • 1970-01-01
  • 2011-07-09
相关资源
最近更新 更多