Dra*_*mmy 6 index database-design sql-server primary-key
我们有一个 SQL Server 解决方案,它有一个表dsStaging.Audit
,用于存储由第三方事务数据库创建的审计记录。我们使用这些审计将来自第三方系统的 CRUD 操作同步到我们的 SQL 数据库中。
CREATE TABLE [dsStaging].[Audit](
[SyncExecutionId] [bigint] NOT NULL,
[AuditDataGuid] [nvarchar](56) NOT NULL,
[AuditDate] [datetime] NOT NULL,
[AuditDateTimeZone] [datetimeoffset](3) NULL,
[AuditEventGroup] [nvarchar](56) NOT NULL,
[TransactionId] [bigint] NOT NULL,
[TransactionSequence] [int] NOT NULL,
.
...
.
CONSTRAINT [PK_Audit] PRIMARY KEY CLUSTERED
(
[SyncExecutionId] ASC,
[TransactionId] ASC,
[TransactionSequence] ASC
) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
)
Run Code Online (Sandbox Code Playgroud)
处理审计后,我想将审计记录移动到一个单独的表中Processed.Audit
,准备在 x 天后删除。
CREATE TABLE [Processed].[Audit](
[SyncExecutionId] [bigint] NOT NULL,
[AuditDataGuid] [nvarchar](56) NOT NULL,
[AuditDate] [datetime] NOT NULL,
[AuditEventGroup] [nvarchar](56) NOT NULL,
[TransactionId] [bigint] NOT NULL,
[TransactionSequence] [int] NOT NULL,
.
...
.
CONSTRAINT [PK_Processed_Audit] PRIMARY KEY NONCLUSTERED
(
[AuditDate] ASC
) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
)
Run Code Online (Sandbox Code Playgroud)
我将审计从暂存阶段转移到处理阶段的主要目标是性能。我需要确保临时表被锁定的时间尽可能短,以便可以尽快处理任何未处理的审计(临时表中的审计较少 = 处理速度更快)。
我们正在寻找周围1.5米审计记录通过这个过程会每隔一小时约10,000批次。
移动审计的过程大约每 20-30 秒触发一次。删除Processed.Audit
记录的过程将每小时执行一次,并从 X 天前(通常大约 7 天)删除 1 小时的审计。
Processed.Audit
表变成聚集索引吗?支持的最低版本:SQL Server 2012 标准版。
Eri*_*ing 12
在这种情况下我想要聚集索引的主要原因是这一行:
删除 process.Audit 记录的过程将每小时执行一次,并从 x 天前(通常大约 7 天)删除一个小时的审计
当您从 HEAP 中删除行时,除非删除获得表锁,或者您向WITH (TABLOCK)
删除查询提供提示,否则数据页可能不会被释放。不过,您可能可以想象这对并发有什么影响。不好。
请注意,TABLOCK
如果您使用 RCSI 或快照隔离,提示将不会有此行为。
这是一个快速示例。加载一个小表:
USE tempdb;
SET NOCOUNT ON;
CREATE TABLE dbo.heap
(
id INT PRIMARY KEY NONCLUSTERED,
junk VARCHAR(1000)
);
INSERT dbo.heap (
id, junk )
SELECT TOP 1000 x.n, REPLICATE('A', x.n % 1000)
FROM (
SELECT ROW_NUMBER() OVER ( ORDER BY @@ROWCOUNT ) AS n
FROM sys.messages AS m ) AS x;
Run Code Online (Sandbox Code Playgroud)
运行健全性检查查询以确定分配给堆和非集群 PK 的页面数量:
SELECT OBJECT_NAME(i.object_id) AS table_name,
i.name AS index_name,
MAX(a.used_pages) AS leaf_me_alone
FROM sys.indexes AS i
JOIN sys.partitions AS p
ON p.object_id = i.object_id
AND p.index_id = i.index_id
JOIN sys.allocation_units AS a
ON a.container_id = p.partition_id
WHERE OBJECT_NAME(i.object_id) = 'heap'
GROUP BY i.object_id, i.index_id, i.name
ORDER BY OBJECT_NAME(i.object_id), i.index_id;
Run Code Online (Sandbox Code Playgroud)
结果如下:
table_name index_name leaf_me_alone
heap NULL 74
heap PK__heap__ 7
Run Code Online (Sandbox Code Playgroud)
因此,堆中有 74 页,NC PK 中有 7 页。
做一些单例删除来清除表:
DECLARE @i INT = 1;
WHILE @i < 1000
BEGIN
DELETE h
FROM dbo.heap AS h
WHERE h.id = @i;
SET @i += 1;
PRINT @i;
END;
Run Code Online (Sandbox Code Playgroud)
如果您重新运行健全性检查查询,您将获得相同的结果。
更糟糕的是,如果您现在查询该表,SQL 将读取所有这些空白页!
SET STATISTICS TIME, IO ON
SELECT *
FROM dbo.heap AS h;
Run Code Online (Sandbox Code Playgroud)
表'堆'。扫描计数 1,逻辑读取 67
所以现在不仅我们的表人为地变大了,而且 SQL 现在在磁盘、内存、备份和 DBCC CHECKDB 中都有一堆空白页……好吧,你明白了。
我们正在查看每小时大约有 150 万条审核记录通过此流程
嘿嘿嘿!没有乐趣。
从堆中释放页面的其他选项是:
TRUNCATE TABLE dbo.heap
Run Code Online (Sandbox Code Playgroud)
这对您不起作用,因为您需要批量删除数据。
ALTER TABLE dbo.heap REBUILD;
Run Code Online (Sandbox Code Playgroud)
在那个表大小下这对您来说会很痛苦,因为它会同时重建表上的所有非聚集索引。
表格会重用页面吗?有时可能有点。
DECLARE @id_max INT = (SELECT MAX(id) FROM dbo.heap AS h);
INSERT dbo.heap (
id, junk )
SELECT TOP 5000 x.n + @id_max, REPLICATE('A', x.n % 1000)
FROM (
SELECT ROW_NUMBER() OVER ( ORDER BY @@ROWCOUNT ) AS n
FROM sys.messages AS m ) AS x;
Run Code Online (Sandbox Code Playgroud)
完整性检查:
table_name index_name leaf_me_alone
heap NULL 400
heap PK__heap__ 20
Run Code Online (Sandbox Code Playgroud)
SELECT * 查询:
表'堆'。扫描计数 1,逻辑读取 392
希望这可以帮助!
归档时间: |
|
查看次数: |
470 次 |
最近记录: |