为啥Sql Indexed View总是使用聚集索引

Posted

技术标签:

【中文标题】为啥Sql Indexed View总是使用聚集索引【英文标题】:Why Sql Indexed View always use Clustered Index为什么Sql Indexed View总是使用聚集索引 【发布时间】:2010-12-16 13:01:12 【问题描述】:

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

环境:SQL Server 2005 Enterprise。

我有一个包含聚集索引和多个非唯一非聚集索引的索引视图。但是,当我执行查询时,SQL Server 总是在我的键上执行聚集索引扫描而不是索引搜索。

这是一个简化版。

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 服务器在 a.Col1 上运行聚集索引扫描,而不是在 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 Server 将不会在索引视图上使用索引。 (也许我应该就创建索引视图的确切步骤提出另一个问题)。

【问题讨论】:

如果查询分析器得出聚集索引扫描比查找更快的结论,它会进行扫描——即使使用索引。这可能与视图中的行数、索引的选择性以及相当多的其他元素有关。仅仅因为存在索引扫描并不意味着索引没有“工作” - 对于那个查询,执行索引扫描可能会更容易。 marc_s - 查看我的更新,我并排运行两个查询,如果 sql 使用索引搜索,它将比集群索引扫描快得多。 【参考方案1】:

我复制了您的示例,并通过 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

执行您的查询

从 MyIndexedView WITH(NOEXPAND) WHERE Col2='blah' 中选择 Col1、Col2、Col3

显示 IX2 上的索引查找

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

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

【讨论】:

感谢您尝试重现该问题。我确实验证了 col2 列上的“使用索引”检查。而且我确实删除并重新创建了索引(不确定它是否与重建相同)。【参考方案2】:

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

如果连接的结果很小,那么扫描聚集索引比寻找另一个更经济有效。

【讨论】:

以上是关于为啥Sql Indexed View总是使用聚集索引的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server的聚集索引和非聚集索引

sql server 索引总结三

为啥在sql server中每张表只能创建一个聚集索引?

为啥 SQL Server 查询优化器有时会忽略明显的聚集主键?

MySQL中怎样创建聚集索引和非聚集索引,求创建这两种索引的SQL语句。谢谢

mongodb为啥比mysql快