为什么Sql Indexed View始终使用Clustered Index

时间:2009-11-14 05:11:22

标签: sql-server-2005

我需要一些关于如何调试以下问题的指针。

环境:SQL Server 2005 Enterprise。

我有一个索引视图,其中包含聚簇索引和多个非唯一的非聚集索引。但是,当我执行查询时,SQL服务器始终执行Clustered index scan而不是我的密钥上的索引搜索。

这是一个简化版本。

CREATE VIEW MyIndexedView WITH SCHEMABINDING
SELECT a.Col1, b.Col2, c.Col3, d.Col4
FROM a JOIN b on a.id = b.id 
       JOIN c on a.id = c.id
       JION d on c.id = d.id

Col1上有一个聚簇索引,Col2,Col3上有非唯一的非聚簇索引。

当我运行以下查询时

SELECT a.Col1, b.Col2, c.Col3 FROM MyIndexedView WITH(NOEXPAND) WHERE b.Col2='blah'

并查看执行计划,我看到SQL Server在a.Col1上运行Clustered index scan而不是在Col2上执行索引查找。

我尝试重新创建视图和索引。

更新: 我做了一些额外的测试,并在查询分析器中并排运行这两个查询。

    a) SELECT a.Col1, b.Col2, c.Col3 
       FROM MyIndexedView WITH(NOEXPAND) WHERE b.Col2='blah'

    b) SELECT a.Col1, b.Col2, c.Col3
       FROM MyIndexedView WHERE b.Col2 = 'blah'

查询'a'将占用95%的时间并使用群集索引扫描。查询'b'只占用5%的时间并在col2上使用Index Seek。我尝试交换查询顺序(先运行b和后运行)产生相同的百分比。

  • 这个小实验证实,如果sql使用索引搜索它将比集群索引扫描更快。
  • 第二我虽然如果我不包含“WITH(NOEXPAND)”,那么SQL服务器将不会在索引视图上使用索引。 (也许我应该就创建索引视图的确切步骤开始另一个问题。)

2 个答案:

答案 0 :(得分:4)

我复制了你的样本,并在Col2上找到索引的预期结果。我能够让它进行聚簇索引扫描的唯一方法是我是否禁用了索引。因此,首先尝试在Col2上重建索引以确保它实际启用(或检查索引属性中的“使用索引”复选框 - 选项)。


以下是我用来创建表格的视图,视图和索引

    CREATE TABLE [dbo].[a](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [Col1] [varchar](100) NOT NULL,
 CONSTRAINT [PK_a] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
CREATE TABLE [dbo].[b](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [Col2] [varchar](100) NOT NULL,
 CONSTRAINT [PK_b] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

CREATE TABLE [dbo].[c](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [Col3] [varchar](100) NOT NULL,
 CONSTRAINT [PK_c] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

CREATE TABLE [dbo].[d](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [Col4] [varchar](100) NOT NULL,
 CONSTRAINT [PK_d] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO


CREATE VIEW [dbo].[MyIndexedView] WITH SCHEMABINDING
AS
SELECT a.Col1, b.Col2, c.Col3, d.Col4
FROM dbo.a JOIN dbo.b on a.id = b.id 
       JOIN dbo.c on a.id = c.id
       JOIN dbo.d on c.id = d.id
GO

/****** Object:  Index [IX]    Script Date: 11/13/2009 21:50:01 ******/
CREATE UNIQUE CLUSTERED INDEX [IX] ON [dbo].[MyIndexedView] 
(
    [Col1] 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

/****** Object:  Index [IX2]    Script Date: 11/13/2009 21:50:39 ******/
CREATE NONCLUSTERED INDEX [IX2] ON [dbo].[MyIndexedView] 
(
    [Col2] ASC,
    [Col3] 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

我填写了这样的表:

declare @x int

SET @x = 0
while @x < 10
begin
INSERT INTO a (Col1 ) VALUES (newid())
INSERT INTO b (Col2 ) VALUES (newid())
INSERT INTO c (Col3 ) VALUES (newid())
INSERT INTO d (Col4 ) VALUES (newid())

SET @x=@x+1
end

执行查询

选择Col1,Col2,Col3来自MyIndexedView WITH(NOEXPAND)WHERE Col2 ='blah'

显示了对IX2的索引搜索

但如果我禁用该索引 ALTER INDEX [IX2] ON [dbo]。[MyIndexedView] DISABLE

然后重新运行,我在MyIndexedView.IX上看到聚集索引扫描

答案 1 :(得分:0)

您的视图中有多少条记录?

如果连接的结果很小,那么扫描聚簇索引比搜索另一个索引更具成本效益。