我们有一个包含以下架构的表:
CREATE TABLE Measurement (
HubId bigint NOT NULL
,DeviceId bigint NOT NULL
,Timestamp datetime NOT NULL
,Value bigint NOT NULL
)
我们希望将记录导入此表中,每秒约100,000条记录将分成多个并发连接。我可以通过将表视为堆(即没有索引)并使用SqlBulkCopy
来实现此级别的性能。每秒都有100,000个唯一的HubId
和DeviceId
组合,Timestamp
递增。 Value
会随着时间的推移而累积。
我们还要求读取最近的两个(在这种情况下为最后一个和倒数第二个 - 插入始终按顺序)值GROUP BY HubId, DeviceId
每秒一次,但仅限于行的子集(用户感兴趣的是产生最后两个值之间的实时差异。
此外,出于历史目的,我们需要每15分钟将数据汇总到15分钟的片段中。此数据基于前15分钟切片的最大值和当前15分钟切片的最大值进行聚合...这需要在整个数据集中进行,但可以跨多个连接分割为唯一HubId
和DeviceId
组合。因为Value
是累积的,所以这实际上是前一个和当前15分钟切片的最后一个值。
使用索引批量插入表会导致升级到独占表锁。此外,我们似乎无法在不升级到独占表锁的情况下执行查询。
有人可以给我一些关于构建这个的最佳方法的指示吗?我正在撞墙,试图找出最好的方法......
谢谢, 迪安
答案 0 :(得分:0)
因此,经过多次改进,我们已经改变了我们的方法,以达到我们所需的吞吐量。事实证明,我们只关注它们在那里的100,000个记录/秒,并且它们用于更新连续滚动的聚合和实时值集。
我们使用多个工作线程将100,000行批量插入临时堆表(因此使用4个工作线程,每个处理大约25,000行),然后将聚簇索引应用于临时表。然后,我们将临时表中的数据直接合并到实时和聚合表中,并删除临时表。这里我们使用ROWLOCK提示强制SQL采用ROWLOCK而不是TABLOCK或PAGLOCK,这会导致工作线程之间的争用超过必要的。
此外,我们将内存中的数据结构更改为有损堆栈而不是队列。在我们的例子中,这是合适的,因为我们通常只关心最新的数据,并且可以删除旧数据。
我们将在我们的口袋中使用分区作为ace,但我们目前仅限于SQL Server标准版,因此我们暂时无法在开发机器之外部署它。
干杯, 迪安