2

我想检查索引视图的查询性能。

我创建了一个基于数据库中所有列的Product表的视图。Northwind创建视图后,我在视图上添加了一个聚集索引(因为我无法在没有 int 的情况下创建非聚集索引)。

现在,在添加非聚集索引之前,我会检查此查询执行计划和统计信息:

SELECT [ProductName]
  ,[QuantityPerUnit]
  ,[UnitPrice]
  ,[UnitsInStock]
  ,[UnitsOnOrder]
  ,[ReorderLevel]
  ,[Discontinued]
FROM [Northwind].[dbo].[test_IndexedView]
WHERE UnitPrice = 21.35

然后我创建一个索引:

CREATE NONCLUSTERED INDEX [idx_Unitp] ON [dbo].[test_IndexedView] 
(
[UnitPrice] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

我再次执行该查询,但没有任何变化。不在执行计划中,不在统计中。

问题出在哪里?如何使用索引视图提高性能?


编辑 1) 我创建一个视图:

CREATE VIEW [dbo].[indexView]
WITH SCHEMABINDING 
AS
    SELECT     ProductName, SupplierID, CategoryID, QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, Discontinued, ReorderLevel
    FROM         dbo.Products
GO

然后当我想在它上面创建一个“非聚集索引”时,就像这样:

CREATE NONCLUSTERED INDEX [idx_Unitp] ON [dbo].[IndexView] 
(
    [UnitPrice] ASC
)

我收到此错误:

消息 1940,级别 16,状态 1,第 1 行
无法在视图“dbo.IndexView”上创建索引。它没有唯一的聚集索引。

所以我被迫创建了一个聚集索引。

索引前后的执行计划都是Index Scan

结果SELECT @@VERSION是:

Microsoft SQL Server 2008 (SP2) - 10.0.4000.0 (Intel X86)
Sep 16 2010 20:09:22 版权所有 (c) 1988-2008 Microsoft Corporation
Enterprise Edition on Windows NT 6.1 (Build 7600: )

4

2 回答 2

2

由于您从表中选择 7 列,并且索引仅包含UnitPrice它自己,因此 SQL Server 查询优化器仍然认为扫描比使用索引查找价格然后必须进行键查找更有效对于找到的每一行以获取其他列。

我几乎敢打赌,如果您像这样在索引中包含其他列

CREATE NONCLUSTERED INDEX [idx_Unitp] 
ON [dbo].[test_IndexedView] ([UnitPrice] ASC)
   INCLUDE(ProductName, QuantityPerUnit, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued)

然后将使用该索引 - 几乎可以肯定。

实际使用非聚集索引的要求非常严格——比大多数人起初所相信的要严格得多。选择性必须非常高 - 有时低于 1% - 才能考虑指数。此外,返回的总行数(以及因此获取其余数据所需的键查找总数)需要很小。

最好的办法是始终拥有一个覆盖索引- 一个包含满足查询的所有信息(所需的所有列)的索引 - 在这种情况下,使用该 NC 索引的可能性会显着增加。

于 2013-04-13T12:57:02.437 回答
1

你说“我被迫创建了一个聚集索引”。但不要给出定义。由于视图上的聚集索引需要是唯一的,我添加ProductID到视图定义中并假设

CREATE UNIQUE CLUSTERED INDEX [idx_Unitp] ON [dbo].[IndexView] 
(
    [UnitPrice] ASC, ProductID ASC
)

然后我通过对基表的扫描看到与您相同的情况

扫描计划

除非我将查询更改为FROM [Northwind].[dbo].[IndexView] WITH (NOEXPAND)在计划确实在视图上显示搜索时使用。

寻求计划

原因在这里解释。最初的查询得到了一个简单的计划,成本仅为0.0033667. 优化器在进行索引视图匹配之前选择此计划。

无论如何,这不是索引视图的好用处。直接在基表上创建索引会更好

CREATE NONCLUSTERED INDEX ixNoView
  ON dbo.Products (UnitPrice)
  INCLUDE ( ProductName, 
            QuantityPerUnit, 
            UnitsInStock, 
            UnitsOnOrder, 
            Discontinued, 
            ReorderLevel) 

这比视图上的聚集索引更窄,因为它只有 7 列而不是 10 列,并且避免了索引视图匹配问题并且更容易被其他开发人员发现。

现在使用非索引视图

CREATE VIEW [dbo].[nonIndexedView]
AS
  SELECT ProductName,
         SupplierID,
         CategoryID,
         QuantityPerUnit,
         UnitPrice,
         UnitsInStock,
         UnitsOnOrder,
         Discontinued,
         ReorderLevel,
         ProductID
  FROM   dbo.Products

查询

SELECT [ProductName]
  ,[QuantityPerUnit]
  ,[UnitPrice]
  ,[UnitsInStock]
  ,[UnitsOnOrder]
  ,[ReorderLevel]
  ,[Discontinued]
FROM dbo.nonIndexedView
WHERE UnitPrice = 21.35

显示索引查找

非索引视图

于 2013-04-14T09:57:53.733 回答