Use*_*r M 14 sql-server clustered-index partitioning
我在 MS SQL Server 中有一个表。
表使用方法:记录从Web Service调用99.9%的使用率从伐木,开发商很少看这个表在正式版(仅当报告或研究的问题)。
主键:基于“INT”数据类型的“ID”。有一个基于“ID”列的聚集索引。
我对此更改的意图:想要管理此表(因为它有 10 年的数据)并继续前进(由于新要求),开发人员/分析师有可能进一步深入研究此表(仅几个月)我不想为同样的目的创建一个新表。
我的问题:
[主要问题]我可以根据“DateCreated”(DATETIME,NOT NULL 列)对这个表进行分区,而不会引起问题(逻辑上/性能方面)。
[很高兴知道] 需要多少时间(我知道这取决于数据库空间/服务器内存和其他细节,但大概# 会很好)对这个巨大的表进行分区(如果可以根据日期进行分区) . 问这个问题,因为这是一个生产表,行被频繁插入(现在大约 350 条记录/分钟)。
【不完全是问题,求推荐】有没有更好的方案来管理这个表(不想在Production中保留3年以上的数据,方案在下面提到)?
当前计划(我是 MS SQL 的新手,所以这就是我想出的):
- 在每个分区中保留 3 个月的数据。
- 系统在每个季度前自动创建分区。
- 在活动表中仅保留 3 年的分区。
- 将其他分区移动到 OLD/ARCHIEVE 表(需要创建这个)。真正要清除的旧数据。
Pet*_*ier 16
简短回答:不,你不能这样做。根据文档...
对聚集索引进行分区时,聚集键必须包含分区列。
这意味着为了在 上分区[DateCreated]
,您还必须在 上集群[DateCreated]
。
当您考虑分区和聚类实际上是什么时,这更有意义。
这两个东西可以一起使用,只要它们不冲突。如果你试图让它们发生冲突,你会过得很糟糕。要逐项回答您的项目:
[DateCreated]
的所有除非删除并重新创建聚簇索引重建对列的表。这是可能的,但这可能是一个比您提出问题时计划的更大的项目。如果您决定一次性执行此操作,则可能会受到磁盘速度的限制。
一个类似的操作是进行备份。备份从这里读取一大堆字节并在那里写入一大堆字节。就像你的桌子重建一样。因此,如果您的数据库是,比如说,1.6TB 并且备份需要 2 小时,那么重建一个 800GB 的表可能需要大约 1 小时(一半的大小,一半的时间)。
当然,这两项任务之间存在很多差异。备份驱动器可能与数据驱动器不同,并发工作负载会影响它们,SAN 的网络路径,二级索引,yadda yadda。所以时间会有所不同,但它们不必有数量级的不同。
与大爆炸相比,您最好按时间相反的顺序一次处理一个用例。
删除要删除的最旧数据。因为有 10 年,而您只想要 3 年,问题立即变得容易 70%!这最好通过一次删除块来完成,而不是在单个查询中全部删除。如果它不能被彻底删除,如何将它移动到 OLAP 服务器或转储为压缩文件格式(parquet、ORC 和它们的同类)?
使用您想要的分区方案创建一个新的空表,并为所有 3 年的历史和一些未来定义分区。首先将最旧的数据分块移动,插入新表并从当前表中删除。我猜 ID 列是一个 IDENTITY,所以它应该与日期分区相关联。如果有人想研究这些旧数据,他们可以从这个新的分区表中进行研究。
最终,您将进入一个阶段,当前未分区表中的唯一数据是当前 3 个月范围内的数据,或者将数据拆分到两个表中会给用户带来实际痛苦。这是停电的时候。将最后一个数据移动到新的分区表,删除当前表并重命名分区表。
[主要问题] 我可以根据“DateCreated”(DATETIME,NOT NULL 列)对这个表进行分区,而不会引起问题(逻辑上/性能方面)。
您可以在DateCreated
将其设为聚集索引后对列进行分区。即使您设法使其成为聚集索引键,也会存在性能问题 - 您的索引将比以前(当 ID INT 聚集时)消耗更多空间(存储/内存)。
因为 INT 是 4 个字节并且是唯一值,但是您的DateCreated
列是 8 个字节并且很可能不是唯一的,因此将在顶部添加额外的 4 字节 uniquifier,在某种程度上使聚集索引更重。由于聚集索引键被添加到所有非聚集索引中,它们也会变得更重
[很高兴知道] 需要多少时间(我知道这取决于数据库空间/服务器内存和其他细节,但大概# 会很好)对这个巨大的表进行分区(如果可以根据日期进行分区) . 问这个问题,因为这是一个生产表,行被频繁插入(现在大约 350 条记录/分钟)。
这完全取决于您服务器的马力
【不完全是问题,求推荐】有没有更好的方案来管理这个表(不想在Production中保留3年以上的数据,方案在下面提到)?
不要使用分区。使用具有相同结构的单独历史表。创建一个每日作业,根据DateCreated
列移动(插入到历史表中/在父表中删除)所有超过 3 年的行。
不是每天一次移动所有行(超过 3 年),而是以 N 行的块为单位移动,块之间的间隔为 X 秒(或毫秒)。N 是每 1 个块删除的行数。确保 N 不会导致父表上的 Exclusive table 锁升级(通过实验找出数字)
不容忽视的一点是,对于 12 亿行,您比您想象的更接近 int 数据类型的上限。所以我认为你的改变也应该计划解决这个限制,可能是改为 Bigint。
正如之前指出的,70% 的数据太旧了,您不再需要保留它,但我会考虑在要保留的 30% 上插入/选择而不是批量删除 70%,然后截断原始表。然后,您可以将行复制回或重命名表。
最后一点是,您的 Id 列可能按升序添加,这样行 < id x 较早,> id x 较晚,因此您可以构建一个映射表,将 id 映射到日期,然后直接在 id 上分区?