2

短背景

大家好。我目前面临的情况是,我需要在 SQL Server 标准版的一个非常大的表上提高性能。该表是事务繁重的,预计会获得更多的事务。

解决方案第 1 部分

我决定使用类似于 Barry King 在这里提出的策略将表分成几个部分。所以我有一堆看起来像下面这样的表格。

CREATE TABLE [NewTable001](
    [DayId] [int] NOT NULL,
    [OriginalTableId] [bigint] NOT NULL,
    [CustomerId] [int] NULL
 CONSTRAINT [PK_OriginalTableID001] PRIMARY KEY CLUSTERED 
(
    [OriginalTableID] 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

ALTER TABLE [NewTable001]  WITH CHECK ADD  CONSTRAINT [CK_Day_001] CHECK  ([DayId]=(1))
GO

ALTER TABLE [NewTable001] CHECK CONSTRAINT [CK_Day_001]
GO

我也有相应的视图来处理所有基础表。现在的问题,正如 Barry King 在他的博客文章中所说,是视图中唯一 ID 的处理。由于视图无法处理 ID,因此它们需要存储在表中并且无法利用身份功能。

解决方案第 2 部分

通过像这样创建一个单独的表:

create table PartitionIDHelper
(
ID bigint identity(10000001,1), --Hihger (with margin) than the higest value in current    table
Value int --Something that is quick to write
);

然后在我的程序中使用此代码:

declare @ID bigint;
insert into PartitionIDHelper
select 1; --Just a value so that I can get the unique ID from the table
select @ID = @@IDENTITY; --My shiny new id value to use when writing to the view</pre>

潜在问题

此解决方案的潜在问题是我可能以错误的顺序将值写入 [OriginalTableID]。

假设进程 A 先于进程 B 启动。进程 A 还在进程 B 之前从 PartitionIDHelper 表中获取 ID。然而,进程 B 更快,并且在进程 B 之前写入,导致在进程 A 之前写入我的聚集索引。

然后,进程 A 不会写入索引中的“最佳”位置,因为它是无序的。

潜在的解决方案

那么如何最好地解决这个问题呢?我可以想到两种策略。

  1. 接受我的聚集索引会稍微出问题
  2. 将每个表中的本地标识列用于聚集索引。

潜在的解决方案 2 在我看来是一条糟糕的道路,因为除了存储顺序之外,我永远不会将该列用于其他任何事情,因为它永远不会被排序、在 where 子句中使用甚至被选中。

在阅读了 Michelle Ufford 的这篇博文(大部分内容)之后,我倾向于坚持使用略微分散的聚集索引。下面的引用对我提出了一个难题,因为数据主要由单例查询访问,但它是一个插入速度很重要的 OLTP 系统。

我并不是建议您只在标识整数列上创建聚集索引。碎片化虽然通常是不可取的,但主要影响范围扫描查询;单例查询不会有太大影响。即使是范围扫描查询也可以从常规碎片整理工作中受益。然而,集群键的不断增加的属性是需要考虑的,并且在插入速度很重要的 OLTP 系统中尤其重要。

任何和所有的意见和建议将不胜感激!

/塔赫

4

0 回答 0