聚集索引的麻烦

时间:2013-08-22 09:07:01

标签: sql sql-server-2008 indexing

在我们的生产系统(SQL Server 2008 / R2)中,有一个表格,用于存储生成的文档。

文档有引用(varchar)和sequence_nr(int)。可以多次生成文档,并且每次迭代都保存在该表中,递增序列号。此外,每条记录都有一个数据列(varbinary)和一个时间戳以及一个用户标记。

查询此表的唯一原因是在以后和插入期间进行审计。

该表的主键聚集在referencesequence_nr列上。

正如您可能猜到的那样,文档的生成以及表格中的数据(因为文档可以在以后再次生成)不会按顺序增长。

我在表中的插入开始超时后意识到这一点。

使用存储过程执行插入。存储过程确定给定引用的当前最大sequence_nr,并使用下一个sequence_nr插入新行。

我很确定聚簇索引选择不当导致超时问题,因为记录将被插入已经存在的引用,只有不同的sequence_nr,因此可能最终在记录集合中的任何地方,但很可能不在结束。

关于我的问题:将非聚集索引作为主键更好或者更好地引入标识列,使其成为聚簇主键并保留引用组合的索引和sequence_nr

暂时知道(并且根本无法预见),除了必须确定新sequence_nr的情况外,无需密集查询此表。

编辑回答问题: Tbh,我不确定生产环境中的超时。我知道在并行运行的进程中添加了新文档。

表:

CREATE TABLE [dbo].[tbl_document] (
    [reference]     VARCHAR(50)    NOT NULL,
    [sequence_nr]   INT            NOT NULL,
    [creation_date] DATETIME2      NOT NULL,
    [creation_user] NVARCHAR (50)  NOT NULL,
    [document_data] VARBINARY(MAX) NOT NULL
);

主键:

ALTER TABLE [dbo].[tbl_document]
    ADD CONSTRAINT [PK_tbl_document] PRIMARY KEY CLUSTERED ([reference] ASC, [sequence_nr] ASC) 
    WITH (ALLOW_PAGE_LOCKS = ON, ALLOW_ROW_LOCKS = ON, PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF, STATISTICS_NORECOMPUTE = OFF);

存储过程:

CREATE PROCEDURE [dbo].[usp_save_document] @reference     NVARCHAR (50),
                                           @sequence_nr   INT OUTPUT,
                                           @creation_date DATETIME2,
                                           @creation_user NVARCHAR(50),
                                           @document_data VARBINARY(max)
AS
  BEGIN
      SET NOCOUNT ON;

      DECLARE @current_sequence_nr INT

      SELECT @current_sequence_nr = max(sequence_nr)
      FROM   [dbo].[tbl_document]
      WHERE  [reference] = @reference

      IF @current_sequence_nr IS NULL
        BEGIN
            SELECT @sequence_nr = 1
        END
      ELSE
        BEGIN
            SELECT @sequence_nr = @current_sequence_nr + 1
        END

      INSERT INTO [dbo].[tbl_document]
                  ([reference],
                   [sequence_nr],
                   [creation_date],
                   [creation_user],
                   [document_data])
      VALUES      (@reference,
                   @sequence_nr,
                   @creation_date,
                   @creation_user,
                   @document_data)
  END 

希望有所帮助。

2 个答案:

答案 0 :(得分:2)

我会设置PK not clustered,因为:

  • 当密钥有varchar时,保持b树平衡,使每个叶子更大。
  • 按照你的说法,你不是一次扫描这张表多行

答案 1 :(得分:1)

由于聚簇索引对表的记录进行物理重新排序以匹配索引顺序,因此仅在您希望按该顺序读出多个连续记录时才有用,因为这样可以通过执行顺序读取来读取整个记录磁盘。

如果您只使用索引中存在的数据,那么将其集群化没有任何好处,因为索引本身(已聚集或未聚集)与数据保持独立并按顺序排列。

因此,对于您的特定情况,非聚集索引是正确的方法。插入不需要重新排序数据(只有索引),只需查看索引就可以找到新的sequence_nr