Остановите выполнение SQL Server ненужной кластеризованной вставки индекса в представление - PullRequest
1 голос
/ 30 октября 2009

У меня есть большая таблица (между 74 и 88 миллионами строк), которая является средней таблицей (Таблица B) отношения многих ко многим. У меня есть представление, которое строит единую картину данных, содержащихся в этих таблицах. Представление имеет кластеризованный индекс, определенный для него.

Таблица A в левой части моей большой таблицы является основной таблицей в моей базе данных. Таблица C - это таблица, содержащая нормализованные элементы данных. Когда я вставляю новую запись в таблицу C, задача занимает много времени (5 минут на очень хорошем сервере). Это потому, что SQL-сервер перестраивает часть кластеризованного индекса в представлении (я вижу вставку кластерного индекса в фактический план выполнения). Это несмотря на то, что новая строка в таблице C не упоминается в таблице B. Вставка строк в таблицу A и таблицу B занимает миллисекунды, как я и ожидал. База данных не разбита на разделы.

Это раздраженная версия скрипта создания таблиц. Я оставил в столбцах, которые не используются, чтобы вы могли увидеть полную структуру таблиц.

CREATE TABLE [dbo].[TableA] (
    [TableAId] [INT] IDENTITY(1,1)  NOT NULL PRIMARY KEY  CLUSTERED ,
    [TableAIdGUID] [uniqueidentifier] NOT NULL,
    [ImportantId] [INT] NOT NULL ,
    [DateCreated] [datetime] NOT NULL ,
    [OtherId2] [int] NOT NULL ,
    [TableATypeId] [int] NOT NULL ,
    [Active] [bit] NOT NULL ,
    [AuditUser] [NVARCHAR] (20) NULL , 
    [AuditTime] [datetime] NULL 
)
GO

CREATE TABLE [dbo].[TableB] (
    [TableBId] [INT]  IDENTITY(1,1)  NOT NULL PRIMARY KEY  CLUSTERED ,
    [TableBGUID]  [uniqueidentifier] NOT NULL,
    [TableAId] [INT] NOT NULL ,
    [TableCId] [INT] NOT NULL ,
    [Tag] [NVARCHAR] (50) NULL , 
    [Order] [tinyint] NOT NULL ,
    [DateCreated] [datetime] NOT NULL ,
    [Date1] [datetime] NULL ,
    [Date2] [datetime] NULL ,
    [LastUpdated] [datetime] NOT NULL ,
    [Active] [bit] NOT NULL ,
    [AuditUser] [NVARCHAR] (20) NULL , 
    [AuditTime] [datetime] NULL
)
GO

CREATE TABLE [dbo].[TableC] (
    [TableCId] [INT] IDENTITY(1,1) NOT NULL PRIMARY KEY  CLUSTERED ,
    [TableCIdGUID]  [uniqueidentifier] NOT NULL,
    [TableCTypeId] [int] NOT NULL ,
    [TableCValue] [NVARCHAR] (255) NOT NULL , 
    [Frequency] [float] NOT NULL  DEFAULT 1,
    [TableCValue2] [NVARCHAR] (255) NULL ,
    [AuditUser] [NVARCHAR] (20) NULL ,
    [AuditTime] [datetime] NULL 
)
GO

CREATE VIEW [dbo].[vwTables]
WITH SCHEMABINDING ,ENCRYPTION
AS

SELECT  dbo.[TableB].TableBId, 
        dbo.[TableB].TableAId, 
        dbo.TableA.ImportantId,
        dbo.TableC.TableCValue,
        dbo.TableC.TableCValue2, 
        dbo.TableC.TableCTypeId,
        dbo.TableA.TableATypeId
FROM    dbo.[TableB] INNER JOIN
        dbo.TableC ON dbo.[TableB].TableCId = dbo.TableC.TableCId INNER JOIN
        dbo.TableA ON dbo.[TableB].TableAId = dbo.TableA.TableAId
WHERE     (dbo.[TableB].Active =  CAST(1 AS BIT)) AND (dbo.TableC.TableCValue<>'') and (dbo.TableC.TableCValue is not null)
GO

CREATE UNIQUE CLUSTERED INDEX [IX_vwTables] ON [dbo].[vwTables] 
(
    [TableCValue] ASC,
    [TableCTypeId] ASC,
    [TableBId] ASC,
    [ImportantId] ASC
)
GO

ALTER TABLE [dbo].[TableB] ADD 
    CONSTRAINT [FK_TableB_TableC] FOREIGN KEY 
    (
        [TableCId]
    ) REFERENCES [dbo].[TableC] (
        [TableCId]
    ),
    CONSTRAINT [FK_TableB_TableA] FOREIGN KEY 
    (
        [TableAId]
    ) REFERENCES [dbo].[TableA] (
        [TableAId]
    )
GO


CREATE NONCLUSTERED INDEX [IX_TableA_Nonclustered] ON [dbo].[TableA] 
(
    [ImportantId] ASC,
    [TableAId] ASC,
    [TableATypeId] ASC,
    [Active] ASC
)
GO

CREATE NONCLUSTERED INDEX [IX_TableA_OtherId2] ON [dbo].[TableA] 
(
    [AuditTime] ASC,
    [OtherId2] ASC
)
GO


CREATE NONCLUSTERED INDEX [IX_TableB_NonClustered] ON [dbo].[TableB] 
(
    [TableAId] ASC,
    [TableBId] ASC,
    [Active] ASC
)
GO

CREATE NONCLUSTERED INDEX [IX_EntityAttributes_NonClustered_2] ON [dbo].[TableB] 
(
    [TableBId] ASC,
    [TableAId] ASC,
    [TableCId] ASC,
    [Tag] ASC,
    [Active] ASC
) 
GO

Ниже приведен пример запроса:

SELECT Query.ImportantId
FROM(

        SELECT  b.ImportantId
        FROM [vwTables] a WITH (NOLOCK)
        INNER JOIN [vwTables] b WITH (NOLOCK, NOEXPAND) ON a.TableCValue = b.TableCValue
        WHERE a.ImportantId = @ImportantId AND
        a.TableATypeId=3 AND b.TableATypeId=3           

) As Query
GROUP BY Query.ImportantId

Кто-нибудь знает, как я могу заставить вставки в таблицу C происходить (почти) мгновенно, как вставки в TableA и TableB?

1 Ответ

3 голосов
/ 30 октября 2009

Если я правильно вас понимаю, у вас есть кластерный индекс в представлении . Когда SQL Server видит, что таблицы под представлением изменяются, он должен переиндексировать представление. Это подходит только тогда, когда таблицы изменяются редко (вспомним базы данных Business Intelligence.)

Рассмотрите возможность удаления индекса из представления и поддержите представление с индексами в базовых таблицах.

Например, см. эту цитату из MSDN:

Q. Я обновляю свое хранилище данных один раз в неделю. Индексированные просмотры ускоряют мой много запросов в течение недели, но замедлить еженедельное обновление? Какие я должен делать?

A. Рассмотрите возможность удаления индексированных представлений. до еженедельного обновления и создания потом снова.

РЕДАКТИРОВАТЬ: Ваш пример запроса появляется для поиска строк в A, которые разделяют TableCValue. Я думаю, что это принесет пользу от этих индексов:

  • Таблица A: (TableATypeId, TableAId)
  • Таблица B: (TableAId, TableCId)
  • Таблица B: (TableCId, TableAId)
  • Таблица C: (TableCValue, TableCId)

С этими индексами можно надеяться, что запрос будет достаточно быстрым, чтобы не требовать индексированного представления.

P.S. Обязательно сравните мое предложение с предложениями по индексированию от SQL Server Profiler на случай, если я что-то пропустил.

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