经常重新填充的大表索引

时间:2017-04-27 10:41:41

标签: c# sql-server indexing sql-server-2012 large-data

我有一组数据(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 个答案:

答案 0 :(得分:1)

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

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

但是,有一些替代方案。

您可以在表所在的数据库中启用读提交的快照隔离(RCSI)。之后,上面描述的所有内容都将由SQL Server本身在窗帘后面执行。

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

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