阻止SQL Server在视图上执行不必要的聚簇索引插入

时间:2009-10-30 14:14:30

标签: sql-server

我有一张大桌子(在74到8800万行之间),这是多对多关系的中间表(表B)。我有一个视图,可以构建这些表中包含的数据的统一图片。视图具有针对它定义的聚簇索引。

我的大表左侧的表A是我数据库中的核心表。表C是包含规范化数据项的表。当我将新记录插入表C时,任务需要很长时间才能完成(在非常好的服务器上5分钟)。这是因为SQL Server在视图上重建了聚集索引的一部分(我可以在实际执行计划中看到聚集索引插入)。尽管表C中没有引用表C中的新行,但是如表所示,将行插入表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 个答案:

答案 0 :(得分:3)

如果我理解正确,您在视图上有聚集索引。当SQL Server发现视图下方的表发生更改时,它必须重新索引视图。这仅在表很少更改时才适用(想想商业智能数据库。)

考虑从视图中删除索引,并支持基础表上带索引的视图。

例如,请参阅MSDN中的this quote

  

Q值。我一次更新我的数据仓库   周。索引视图加快了我的速度   在一周内查询了很多,但是   减慢每周更新?什么   我该怎么办?

     

一个。考虑删除索引视图   在每周更新和创建之前   他们之后再次。

编辑:您的示例查询似乎在A中搜索共享TableCValue的行。我认为它会受益于这些指数:

  • 表A :( TableATypeId,TableAId)
  • 表B :( TableAId,TableCId)
  • 表B :( TableCId,TableAId)
  • 表C :( TableCValue,TableCId)

使用这些索引,您希望查询足够快,不需要索引视图。

P.S。在我遗漏某些内容时,请务必将我的建议与SQL Server Profiler中的索引建议进行比较。