索引具有两个同样查询的日期时间列的表的最佳方法

Nik*_*Nik 6 database-design sql-server-2008-r2

Sql Server 2008 R2。

我有一个包含 ~70m 记录的表,每秒大约插入 10 次。

它当前聚集在 CreatedAt 日期时间列上,该列始终增加。50% 的查询涉及此列。

还有另一个日期时间列“IssuedAt”,它具有不同的含义,但通常在 CreatedAt 的一天左右。50% 的查询涉及此列。此列上的 NC 索引。

还有许多其他 FK 列 - 如果相关,可能大约 150 字节宽。还有一些索引 - 以不同方式对表格进行大量查询以获取各种报告。

我的问题是针对聚集索引和两个日期时间列索引该表的最佳方法。

a)我担心聚集键比它必须的大(日期时间+隐式鉴别器)导致更大的NC索引大小。我应该添加一个 INT 身份,而不是集群吗?

b) 由于书签查找,我对 IssuedAt 列的查询可能很昂贵。我面临着在其中包含越来越多的列(损害写入性能)。这里有替代策略吗?

提前致谢。

更新:

只是为了清楚起见 - 我知道需要进行基准测试 - 我可以看到一些查询没有得到令人满意的满足。

50% 的查询依赖于具有 CI 的日期时间列 A 和 50% 的依赖于具有 NCI 的日期时间列 B 之间存在固有的紧张关系。我希望可能有某种值得考虑的方法/技巧来抵消这种紧张局势。例如,一个新的过滤索引,或者移动到一个聚集索引,如果它们匹配,它是两者的日期组件,或者其他人用来缓解这种紧张局势的其他技术。

第二次更新:

我现在正在考虑以下几点:

  1. 创建一个新列: IssuedAtOffset (int)。这是 CreatedAt 和 IssuedAt 之间的差异,以秒为单位。我从业务现实中知道 int 足以捕获这个增量,而且 IssuedAt 的毫秒数是无关紧要的,所以这会起作用。

  2. 将 IssuedAtOffset 更新为正确的值。

  3. 丢弃发布于。

  4. 现在创建 CI:CreatedAt + IssuedAtOffset。

  5. 创建一个视图,其中 IssuedAt 作为基于 CreatedAt + IssuedAtOffset 的计算列返回。

因此,当我查询该视图时,可以直接从 CI 提供针对 CreatedAt 或 IssuedAt 的任何查询。这将意味着更多的 CPU,因为必须为每一行添加更多的 CPU,但我猜这与 IO 节省相比微不足道(当然仍需进行基准测试)。

我错过了这里的任何缺点/问题吗?

第三次更新:

我创建了两个表来测试上面的这种方法,结果并不完全符合我的预期。

T1 代表当前设置:

CREATE TABLE [dbo].[t1](
[CreatedAt] [datetime] NULL,
[IssuedAt] [datetime] NULL,
[Col1] [varchar](20) NULL,
[Col2] [char](4000) NULL
Run Code Online (Sandbox Code Playgroud)

) 在 [主要]

一列上的 CI。

CREATE CLUSTERED INDEX [IX_Clustered] ON [dbo].[t1] 
Run Code Online (Sandbox Code Playgroud)

( [CreatedAt] ASC )

第二个日期时间列上的 NCI。

CREATE NONCLUSTERED INDEX [IX_t1_NC] ON [dbo].[t1] 
Run Code Online (Sandbox Code Playgroud)

( [IssuedAt] ASC )

T2 代表建议的设置:

CREATE TABLE [dbo].[t2](
[CreatedAt] [datetime] NULL,
[IssuedAt] [datetime] NULL,  ---this would be dropped in due course
[Col1] [varchar](20) NULL,
[Col2] [char](4000) NULL,
[IssuedAtOffset] [int] NOT NULL
Run Code Online (Sandbox Code Playgroud)

) 在 [主要]

两列上的单个 CI。

CREATE CLUSTERED INDEX [IX_t2_CI] ON [dbo].[t2] 
Run Code Online (Sandbox Code Playgroud)

( [CreatedAt] ASC, [IssuedAtOffset] ASC )

我将 100k 条记录插入 t1,将它们复制到 t2,并将 IssuedAtOffset 设置为 T2 中的正确值。

我创建了一个视图来简化处理 T2:

create view [dbo].[t2v] 
Run Code Online (Sandbox Code Playgroud)

as select createdat, dateadd( second, issueatoffset, createdat) as 'IssuedAtO', col1, col2 from t2

所以现在是确认性能变化的时候了:

在旧桌子上:

select col2 from t1 where createdat < '2013-01-30'
Run Code Online (Sandbox Code Playgroud)

正如预期的那样,在 IX_Clustered 上进行 CI 搜索。

select col2 from t1 where issuedat  < '2013-01-30'
Run Code Online (Sandbox Code Playgroud)

使用 NCI,然后按预期进行密钥查找。

在新表上:

select col2 from t2v where createdat < '2013-01-30'
Run Code Online (Sandbox Code Playgroud)

正如预期的那样,使用聚集索引查找。

CPU:0,读取:3,持续时间:0

现在,有趣的部分是:从 t2v 中选择 col2,其中 IssuedAtO < '2013-01-30' 使用聚集索引 SCAN。 CPU:62,读取:61094,持续时间:61

由于 dateadd 功能,我期待更高的 CPU。很高兴它使用了 CI,因为没有书签查找来获取 Col2 数据。

但不确定我是否期待扫描 - 读取已经通过屋顶,大概是因为这是扫描,而不是搜索。

这可能会降低这种方法的预期好处 - 为什么它会更改为扫描,有什么方法可以构建 CI 使其成为搜索?

谢谢你。

A-K*_*A-K 8

基准测试是无可替代的。为了回答这个问题,我会创建并填充几个可能的表。然后我会将这些表暴露给您的典型工作负载和基准测试。

在您的 NCI 中包含其他列将减慢修改速度并加快选择速度。根据两者的频率,我们可以选择使用较少资源的方法。如果一行平均每年读取两次,与每行平均每分钟读取两次的情况相比,您的结论可能会有所不同。

此外,并非所有查询都是生来平等的。如果某些查询无论如何都必须在特定时间内完成,那么您必须确保满足这些要求。显然,这种要求胜过上述共同利益的方法。只有您才能知道实际要求。