2009-10-30 58 views
1

做一个不必要的聚簇索引插入我有一个大表(74个88million行之间),这是中间表(表B)一个多对多关系。我有一种观点,即构建这些表格中包含的数据的统一图片。该视图具有针对它定义的聚集索引。我的大桌子的左侧停止SQL Server上的图

表A是我的数据库中的核心表。表C是包含规范化数据项的表。当我在表C中插入新记录时,任务需要很长时间才能完成(非常非常好的服务器上需要5分钟)。这是因为SQL Server重建视图上的聚集索引的一部分(我可以在实际的执行计划中看到聚集索引插入)。尽管表C中的新行没有在表B中被引用,但在表A和表B中插入行需要几毫秒,正如我所期望的那样。数据库未分区。

这是表创建脚本的annoymised版本。我已经留在未使用的列中,因此您可以看到表格的完整结构。

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中发生的(几乎)瞬间像插入到表A和表B?

+0

请张贴一些代码,特别是视图及其索引的CREATE。但是,是的......如果视图(因此索引)具有来自所有三个表格的字段,则这意味着要改变的索引可能会缓慢,这取决于情况。 (5分钟确实看起来很奇怪,但是再次看到视图上的集群ix有点奇怪;-)) – mjv 2009-10-30 14:24:41

+1

你能解释表C中的新行未被表B引用吗?也许你需要显示你的表结构,你的视图的代码和导致问题的INSERT语句。 – 2009-10-30 14:31:11

+0

您是否曾尝试将TableC.TableCId添加到vwTables以及作为聚簇索引IX_vwTables中的第一列? – 2009-10-30 14:59:36

回答

3

如果我理解正确的话,你有一个观点聚集索引。当SQL Server发现视图下方的表发生更改时,它必须重新对视图进行索引。当表更改很少(认为商业智能数据库。)

考虑从视图中删除索引,支持与基础表上的索引视图这仅仅是合适的。

例如,见this quote从MSDN:

问:我更新一次,每周 我的数据仓库。索引视图加快我 在本周查询了很多,但 减慢每周更新?我应该怎么做 ?

答:考虑在每周更新之前删除索引视图 ,并在之后再次创建 。

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

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

有了这些索引,您希望查询速度足够快,从而不需要索引视图。

P.S.请务必将我的建议与来自SQL Server Profiler的索引建议进行比较,以免我错过了某些内容。

+0

底层表格确实有索引,但我们需要对视图进行索引以获得我们需要的性能级别。 – 2009-10-30 14:47:23

+0

在我们进行批量更新之前,视图上的索引被禁用,但问题来自我们的涓流更新系统。更新需要在数据库运行时进行。 – 2009-10-30 15:01:36

+0

+1:这是要走的路....问题的根本原因是视图的基础表,这是需要进行性能调整的地方。从源头上解决问题。 – 2009-10-30 15:07:27