Почему Sql Indexed View всегда использует Clustered Index - PullRequest
1 голос
/ 14 ноября 2009

Мне нужен указатель на то, как отладить следующую проблему.

Среда: SQL Server 2005 Enterprise.

У меня есть индексированное представление, содержащее кластеризованный индекс и несколько неуникальных некластеризованных индексов. Однако, когда я выполняю запрос, SQL-сервер всегда выполняет сканирование кластеризованного индекса вместо поиска индекса по моему ключу.

Вот упрощенная версия.

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.

Я пытался воссоздать представление и индекс.

Обновлено: Я провел дополнительное тестирование и параллельно выполнил эти два запроса в Query Analyzer.

    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. Я пытаюсь поменять местами порядок запросов (сначала запустить b, а потом), чтобы получить одинаковый процент.

  • Этот небольшой эксперимент подтверждает, что если sql использует поиск по индексу, это будет быстрее, чем сканирование индекса кластера.
  • Во-вторых, если я не укажу «WITH (NOEXPAND)», SQL-сервер не будет использовать индекс в индексированном представлении. (Может быть, я должен начать другой вопрос о точном шаге для создания индексированного представления).

Ответы [ 2 ]

4 голосов
/ 14 ноября 2009

Я воспроизвел вашу выборку и получил ожидаемые результаты с поиском индекса по 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 С (NOEXPAND) ГДЕ Col2 = 'бла'

показывает поиск индекса по IX2

но если я отключу этот индекс ALTER INDEX [IX2] ON [dbo]. [MyIndexedView] DISABLE

и перезапустите, я вижу сканирование кластерного индекса на MyIndexedView.IX

0 голосов
/ 14 ноября 2009

Сколько записей на ваш взгляд?

Если результат объединения невелик, то наиболее выгодно сканировать кластерный индекс, чем искать другой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...