Tho*_*hor 4 performance sql-server
许多应用程序将日志记录信息存储在日志表中。
这些表很特殊,因为您只会执行插入操作。你永远不会进行更新。如果您确实进行了删除,那么清除旧数据将是一项每晚的工作。
该表有一个日期时间字段,该字段通常严格递增。调用应用程序可能会失去与数据库的连接,并且会堆积插入,并且在它获得连接时,它不能保证它将按照严格的顺序执行插入。但总的来说,如果日期时间字段是聚集索引,我预计在插入时对表进行排序会很便宜。
大多数查询将查询日期时间,但这些将是不等式查询。
有了这些特殊的属性,感觉应该有一种方法来优化它。
最佳实践是什么?
日志表的示例可以是:
CREATE TABLE logMessages (
logTime datetime2(6) NOT NULL,
logSeverity varchar(10) NOT NULL,
logStatus varchar(10) NOT NULL,
logText varchar(255),
processID bigint,
processUser varchar(25)
)
Run Code Online (Sandbox Code Playgroud)
一个典型的查询:
SELECT logTime, logSeverity, logText
FROM logMessages
WHERE logTime >= '2020-10-01'
AND logTime < '2021-11-01'
AND logSeverity IN ('WARNING','ERROR','FATAL')
Run Code Online (Sandbox Code Playgroud)
唯一身份?
日期时间字段不唯一,我们是否需要唯一标识符?
选项 1:添加logId BIGINT IDENTITY列
如果我们添加一个唯一的 logId,它将不会在任何其他表中用作外键。
如果我们单独使用它作为聚集索引,并且 SQL Server 认为我们的查询将检索太多行而无法使用非聚集索引,那么它将执行全表扫描。
将聚集索引设置为 (logTime, logId) 是否有意义?我想要这样做的原因是,当查询优化器不会在 logTime 上使用非聚集索引时,因为它需要太多行,那么依靠良好的聚集索引将减少要扫描的行数。
选项 2:不添加 logId
将聚集索引设置为 (logTime)。由于 logTime 不是唯一的,SQL Server 必须通过添加不可见列来使其唯一。这是一个问题吗?至少我得到了一个良好的聚集索引,这将有助于我的大多数查询。
查找表
logSeverity 是一个带有预定义值(DEBUG、INFO、WARNING、ERROR、FATAL)的小 int,将这些值移动到不同的表并用tinyint 表示它们是否会更好?
查询提示:WITH (NOLOCK)
WITH (NOLOCK)专家通常表示,如果不需要准确的数据,则可以使用。是否有任何情况下您可以使用它并仍然获得准确的数据?在这种情况下,我们不会执行 UPDATE 或 DELETE,而只会执行 INSERT。插入通常也位于表的末尾(日期时间字段将增加)。不会查看最后几秒的查询不应受到插入的影响。
把它们加起来:
谢谢。
直接回答您的每个问题:
问:关于唯一密钥我们该怎么办? 问:我们的聚集索引应该怎样?
答:在大多数情况下,拥有一个很重要,primary key这样您就可以保证唯一性(包括本例)。仅在临时表中,不使用它可能是例外。它甚至可能对以后的即席调试有用,并且使用INT或BIGINT自动增量字段作为一个字段很便宜。但是出于性能原因,您仍然可以(并且应该)将 logTime 列放在clustered index表上,因为它将在许多查询中用作谓词,并且从性能角度来看,SQL Server 所做的唯一标识符步骤是超级可以忽略不计的。如果您确实添加 LogId 作为主键,则可以nonclustered index向其添加 a。这样,如果您需要进行任何临时维护(例如删除/更新表中的特定记录,您可以通过主键有效地查找它们)。
问:我们应该使用查找表吗?
答:在这种情况下,我建议使用查找/“枚举”表。从节省空间或性能的角度来看,这并不是什么,但主要是因为如果其中一个值发生变化,您可以通过仅更新查找表来非常有效地维护它,而不是必须更新主表中引用该值的每条记录。从数据完整性角度来看,这是一个改进。它还可以防止锁定较大的主表(因此也有一些性能优势)。
问:我们可以使用WITH(NOLOCK)吗?
答:您不可能在此处使用WITH (NO LOCK) 查询提示并保证始终拥有100% 准确的数据,即使您从与 或 不同的行集中进行INSERTED选择UPDATED。我过去维护过确实使用它的查询,并且很少遇到问题,但我个人的选择(除非不关心数据准确性)是避免它。对于查询调优,有更好的性能改进替代方案。顺便说一句,我曾经对 NOLOCK 提示也有过同样的想法,您可以看到 Microsoft 的 David Browne 对我的问题的回答,以了解为什么无法保证数据准确性的决定性原因。简而言之,您选择的行可能是不断变化的数据结构的一部分,因为其他较远的行正在INSERTED或UPDATED同时也是同一数据结构的一部分,例如特定的 B 树,index两行都是一部分的。
问:还有其他最佳实践吗?
答:也许考虑其他可能需要查询日志的方式,例如特定用户、特定进程或两者的所有日志(甚至无论它们何时发生)?如果是这样,在这些字段上添加一些额外的内容nonclustered indexes也可以在以后对您有所帮助。例如,nonclustered index在 processUser、processID 上,然后单独nonclustered index在 processID 上(第一个index将覆盖仅使用 processUser 的谓词,或者使用 processUser 和 processID,这就是为什么您不需要nonclustered index仅在 processUser 上的第三个)。
| 归档时间: |
|
| 查看次数: |
4494 次 |
| 最近记录: |