如何重新索引AuditLog表?非聚集主键,聚簇覆盖索引,guid

时间:2018-02-24 11:38:20

标签: sql-server database indexing

使用SQL Server 2016 Standard。我有一个现有的AuditLog表,在bigint列上有一个PK(生成的C#侧)和一个附加索引。

CREATE TABLE [dbo].[AuditLog]
(
    [Id] [bigint] NOT NULL,
    [ChangeTime] [datetime] NOT NULL,
    [User] [varchar](100) NOT NULL,
    [RootId] [bigint] NOT NULL,
    [EntityId] [bigint] NOT NULL,
    [EntityName] [varchar](100) NOT NULL,
    [Operation] [varchar](100) NOT NULL,
    [OldValue] [varchar](max) NULL,
    [NewValue] [varchar](max) NULL
)

ALTER TABLE [dbo].[AuditLog] 
    ADD CONSTRAINT [PK_AuditLog] 
        PRIMARY KEY CLUSTERED ([Id] ASC)

CREATE NONCLUSTERED INDEX [IX_AuditLog_RootId] 
    ON [dbo].[AuditLog] ([RootId] ASC)

使用当前的105,000,000行,大小为(使用used_pa​​ge_count *每页8K):

  • PK_AuditLog:11,535,112 KB
  • IX_AuditLog_RootId:2,370,480 KB

我现在必须从SQL中的存储过程创建此表中的行,而不再是c#中的行,所以我需要一个可以生成SQL端的主键(和C#仍然)。我认为我的选择是int identityguid(默认为NEWSEQUENTIALID)。

由于我的大部分用法都包括按日期排序的日期和顺序,因此我正在考虑将其与此进行聚类。听起来不错?

由于我几乎总是按RootIdUser进行过滤,因此我想将它们包含在我的索引中。将其他列包含在聚簇索引中是一个好主意吗?或者他们应该在一个单独的覆盖索引?

每个索引都需要唯一标识行,因此即使我没有指定主链,我的聚簇索引也会包含主键。所以使用Guid作为PK似乎是存储的一个坏主意,特别是有1亿行。所以我使用的是bigint

由于我的PK不是聚集的(因此没有以该顺序物理存储),SQL Server如何计算下一个身份?我怀疑它是否对PK进行排序以找到最大值。在非聚集列上使用标识是个坏主意吗?

另外,我想我可以使用datetime2精度为3(存储7个字节)而不是datetime(8个字节)来保持相同的精度,但节省了一点空间(甚至精度4到无论如何都要提高相同存储的精度)?

所以我正在考虑这样做:

CREATE TABLE dbo.AuditLog
(
    Id bigint NOT NULL IDENTITY (1, 1),
    ChangeTime datetime2(4) NOT NULL...


ALTER TABLE AuditLog   
    ADD CONSTRAINT [PK_AuditLog] 
        PRIMARY KEY NONCLUSTERED (Id)

CREATE CLUSTERED INDEX CIX_AuditLog_ChangetimeRootUser 
    ON AuditLog(Changetime, RootId, [User])

脚注

这是表格的使用方式:

  • 此表中没有外键。

  • 插入沉重(任何添加/编辑/删除用户实体字段,在工作时间内不断插入新的AuditLog行,必须快速)

  • 偶尔读取(用户检查什么或谁改变了一些东西,即每天读几次AuditLog会很高兴不等待查询返回的年龄)

  • 一旦插入,AuditLog行永远不会更新或删除。

典型的过滤器和订单:

  • 仅按日期过滤
  • 按日期和用户过滤
  • 按日期和objectId过滤
  • 按日期和用户及objectId过滤
  • 仅按objectId过滤
  • 几乎总是按反向日期排序,以便首先显示最近的更改。
  • 经常与分页一起使用,使用“offset x rows”和“fetch next x rows only”
  • 和一个特定的用例,相当于使用where子句选择PK的子集,然后使用PK自行连接主表以检索列值

PS:我清楚过程和时间,创建临时新表,以块的形式复制数据,创建索引等......

1 个答案:

答案 0 :(得分:1)

由于我的大多数用法包括按日期排序的日期和顺序,我正在考虑使用它进行聚类。听起来不错?

没有这样做并且评估结果就没有办法知道。

在聚集索引中包含其他列是否是个好主意?

您不能在聚集索引中包含列,因为它没有多大意义。聚簇索引最终表。您在NC索引中包含列以避免进行其他查找以访问行的其他列。

SQL Server如何计算下一个身份?

坦率地说,不要担心。引擎管理表级别的标识 - 它不需要引用任何特定行来确定下一个值。

另外,我想我可以使用datetime2和精度3(存储7字节)而不是datetime(8字节)来保持相同的精度但节省一点空间(甚至精度4以提高相同存储的精度)反正)?

请勿仅限每行保存一个字节。根据您的要求选择正确的数据类型。存储很便宜。缺乏精确性是永远的。

此外,您的脚注不清楚。您指的是添加/更新/删除用户实体字段(对于那些不熟悉您的模式的人来说这是一个毫无意义的术语),也指“从不更新或删除”。这似乎是一个矛盾,可能相关也可能不相关。

最后一条评论。变革涉及风险。如果您当前的架构已足够,那么最安全方法是简单地使用您的ID列作为标识重新创建您的表(并且其他所有内容保持不变)。