经常重新填充的大表索引

Posted

技术标签:

【中文标题】经常重新填充的大表索引【英文标题】:Frequently repopulated large tables indexes 【发布时间】:2017-09-25 02:40:08 【问题描述】:

我有一组数据(2M+ 行),我需要每隔几分钟重新填充一次。在此期间也必须访问数据,因此我们有这个解决方案:

我们有两个表 Table_First 和 Table_Second 我们有一个视图 TableView 指向其中一个表(Simple SELECT list_of_columns FROM Table_XXXX)

当视图指向 Table_First 时,我们:

在 Table_Second 上禁用索引 截断 Table_Second 通过 SqlBulkCopy 并行填充 在 Table_Second 上重建索引 更改 TableView,使其现在指向 Table_First

您认为这是一个好的设计,还是我们可以做得更好?

我在想,每次重建索引后,统计信息都会丢失,并且每个从 TableView 中选择数据的查询都会被重新编译。我应该担心吗?

另一个原因是重建实际上有时比数据插入需要更多的时间。

作为替代方案,我们可以只将行插入临时表(或持久表),然后使用带有 INSERT、UPDATE 和 DELETE 的 MERGE 更新数据。

表格如下所示:

CREATE TABLE [dbo].[Table_First](
[GroupId] [int] NOT NULL,
[ItemId] [int] NOT NULL,
[SKU] [nvarchar](255) NOT NULL,
[PropertyId] [int] NOT NULL,
[StringValue] [nvarchar](500) NULL,
[DecimalValue] [float] NULL,
[PropertyValueId] [int] NULL) ON [PRIMARY]

CREATE CLUSTERED INDEX [IX_Index1] ON [dbo].[Table_First]
(
    [GroupId] ASC,
    [PropertyId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
GO

CREATE NONCLUSTERED INDEX [IX_Index2] ON [dbo].[Table_First]
(
    [SKU] ASC,
    [PropertyId] ASC
)
INCLUDE ([PropertyValueId]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
GO

不幸的是,表中的数据不是唯一的。

【问题讨论】:

【参考方案1】:

您的解决方案可能是可行的,尽管它取决于许多方面,例如您的阅读负荷。这里的主要瓶颈是:

ALTER VIEW 语句在视图上放置的 Sch-M 锁,在此期间没有其他会话可以访问它。如果你能忍受它,很好; 更改视图将导致重新编译所有使用它的查询。如果您的查询很少,这可能是可以容忍的。

但是,有一些替代方案。

您可以在表所在的数据库中启用已提交读快照隔离 (RCSI)。之后,上述所有内容都将由 SQL Server 自己在幕后执行。

您可以使用表分区来进行投标。通过切换新部分和旧部分,它将与您的原始计划基本相同,尽管可能存在一些显着差异。但是,并非每个版本的 SQL Server 都支持表分区。

我自己并没有玩太多,但是从 SQL Server 2014 开始,有一个不错的功能,即内存表。它们减少了锁争用和磁盘占用,因此可能值得研究。

【讨论】:

以上是关于经常重新填充的大表索引的主要内容,如果未能解决你的问题,请参考以下文章

MySQL 对于千万级的大表要怎么优化

在 PySpark 中重新索引和填充缺失的日期

分区大表 - 索引

oracle 大表怎么建索引

pandas基础运算

根据不均匀的日期重新索引熊猫数据框,然后用 groupby 和空白填充某些值