如何在重建非常大表的索引时保留较小的事务日志文件

rda*_*pan 5 sql-server transaction-log columnstore sql-server-2016 bulk-insert

我需要我所能获得的所有帮助才能成功重建索引。特别是有关事务日志管理的专家建议。

背景

目标数据库是在聚集列存储索引 (CCIX) 中托管 3 个大表的 DW 数据库。最大的表叫做模拟。它拥有约 370 亿行和约 600 GB 的高压缩数据。根据我们使用较小表的初步估计,150 GB CCIX 表可以扩展到 5 TB,因此我们为这次重建提供了额外的 29 TB。

  • SQL Server 企业版 2016
  • 恢复模式 = 简单

为什么我们必须这样做?

在我们的 ETL 服务的第一个版本中,数据在加载到 CCIX 之前没有先合并和排序。这导致 CCIX 的非最佳使用,因为许多行段在压缩之前没有完全填充。最佳段必须压缩 1,0485,76 行,并且必须按时间排序,以便基于时间的查询可以在 sql server 中获得最多的行组消除,并减少要处理的段。随着更多的文档可用,我们将学习更多的 CCIX。

我的对齐摘录在这里 https://drive.google.com/file/d/0BzGLNskaj70UQUtZYW9CZF9iUUk/view?usp=sharing

新的 ETL 保证数据在加载到 CCIX 之前及时整合和排序。所以未来的加载将被排序,我们在这里关注的是在首次加载期间加载的现有数据。

有关完整的案例描述,请阅读此处。 https://drive.google.com/open?id=0BzGLNskaj70URmZURlVDWVNYd2M

这是我们的第二次尝试,尽管新脚本具有基于分区的索引重建,但我可以看到日志文件仍在堆积。我们需要控制这一点。

我的问题是:

  1. 我已经执行了第二次尝试(正在进行),是否可以检查哪些分区已经被处理和排序?我在重建脚本中有 OFFLINE = ON 。

  2. 当基于分区的索引重建正在进行时,我们如何管理事务日志的大小?我们需要对此进行检查,并在可能的情况下定期截断每个分区。

  3. 由于日志文件中的空间不足,索引重建最初失败。我们添加了一个新的日志文件并使用单独的磁盘。但是我们如何确保这不会在第二次运行中再次发生?基于分区的重建是否足以保证我们能够成功重建?

感谢你的帮助。

按分区重建脚本(第二次尝试)——进行中

已用时间:17 小时 34 分钟

--create a new clustered row index (CRI)
CREATE CLUSTERED INDEX [Analog_ColumnStoreIndex] 
ON [dbo].[Analog]
(
    [LogTime] ASC,
    [CTDIID] ASC,
    [WindFarmId] ASC,
    [StationId] ASC
) 
WITH (
    DROP_EXISTING = ON,
    PAD_INDEX = OFF, 
    STATISTICS_NORECOMPUTE = OFF, 
    SORT_IN_TEMPDB = OFF,
    ALLOW_ROW_LOCKS = ON, 
    ALLOW_PAGE_LOCKS = ON,
    ONLINE = OFF
) 
ON [AnalogMonthlyPScheme]([LogTime])
GO
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

Pau*_*ite 1

我一次会处理这个分区。高层次上:

  1. 使用分区聚集行存储索引创建新的空目标表
  2. 创建具有未分区聚集列存储索引的工作表
  3. SWITCH源表到工作表的分区1
  4. 使用以下命令将工作表转换为行存储聚集索引DROP_EXISTING
  5. 向工作表添加一个CHECK约束,覆盖分区 1 中的值范围
  6. SWITCH将工作表放入目标表的分区1
  7. 删除空工作表
  8. 对下一个分区重复步骤 2
  9. 处理完所有分区后,删除原始表,然后重命名新表

这可以最大限度地利用最少日志记录的操作,最大限度地减少工作空间,并允许在必要时清除分区之间的事务日志。

演示

分区

CREATE PARTITION FUNCTION [AnalogMonthlyP] (datetime2(0))
AS RANGE RIGHT FOR VALUES(
N'2014-09-01T00:00:00.000', N'2014-10-01T00:00:00.000', N'2014-11-01T00:00:00.000',
N'2014-12-01T00:00:00.000', N'2015-01-01T00:00:00.000', N'2015-02-01T00:00:00.000',
N'2015-03-01T00:00:00.000', N'2015-04-01T00:00:00.000', N'2015-05-01T00:00:00.000',
N'2015-06-01T00:00:00.000', N'2015-07-01T00:00:00.000', N'2015-08-01T00:00:00.000',
N'2015-09-01T00:00:00.000', N'2015-10-01T00:00:00.000', N'2015-11-01T00:00:00.000',
N'2015-12-01T00:00:00.000', N'2016-01-01T00:00:00.000', N'2016-02-01T00:00:00.000',
N'2016-03-01T00:00:00.000', N'2016-04-01T00:00:00.000', N'2016-05-01T00:00:00.000',
N'2016-06-01T00:00:00.000', N'2016-07-01T00:00:00.000', N'2016-08-01T00:00:00.000',
N'2016-09-01T00:00:00.000', N'2016-10-01T00:00:00.000', N'2016-11-01T00:00:00.000',
N'2016-12-01T00:00:00.000', N'2017-01-01T00:00:00.000', N'2017-02-01T00:00:00.000',
N'2017-03-01T00:00:00.000', N'2017-04-01T00:00:00.000', N'2017-05-01T00:00:00.000',
N'2017-06-01T00:00:00.000', N'2017-07-01T00:00:00.000', N'2017-08-01T00:00:00.000',
N'2017-09-01T00:00:00.000', N'2017-10-01T00:00:00.000', N'2017-11-01T00:00:00.000',
N'2017-12-01T00:00:00.000', N'2018-01-01T00:00:00.000', N'2018-02-01T00:00:00.000',
N'2018-03-01T00:00:00.000', N'2018-04-01T00:00:00.000', N'2018-05-01T00:00:00.000',
N'2018-06-01T00:00:00.000', N'2018-07-01T00:00:00.000', N'2018-08-01T00:00:00.000',
N'2018-09-01T00:00:00.000', N'2018-10-01T00:00:00.000', N'2018-11-01T00:00:00.000',
N'2018-12-01T00:00:00.000');

CREATE PARTITION SCHEME [AnalogMonthlyPScheme]
AS PARTITION [AnalogMonthlyP]
ALL TO ([PRIMARY]);
Run Code Online (Sandbox Code Playgroud)

数字表设置(如果需要)

WITH Ten(N) AS 
(
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
)   
SELECT TOP (10000000) 
    n = IDENTITY(int, 1, 1)
INTO   dbo.Numbers
FROM   Ten T10,
       Ten T100,
       Ten T1000,
       Ten T10000,
       Ten T100000,
       Ten T1000000,
       Ten T10000000;

ALTER TABLE dbo.Numbers
ADD CONSTRAINT PK_dbo_Numbers_n
PRIMARY KEY CLUSTERED (n)
WITH (SORT_IN_TEMPDB = ON, MAXDOP = 1, FILLFACTOR = 100);
Run Code Online (Sandbox Code Playgroud)

源表和数据

-- Source table currently partitioned clustered columnstore
CREATE TABLE [dbo].[Analog]
(
    LogTime datetime2(0) NOT NULL,
    CTDID integer NOT NULL,
    WindFarmId integer NOT NULL,
    StationId integer NOT NULL,

    INDEX [Analog_ColumnStoreIndex]
        CLUSTERED COLUMNSTORE
)
ON [AnalogMonthlyPScheme](LogTime);

-- Some test data
INSERT dbo.Analog WITH (TABLOCKX)
    (LogTime, CTDID, WindFarmId, StationId)
SELECT
    DATEADD(SECOND, N.n, '20140801'),
    CHECKSUM(NEWID()),
    CHECKSUM(NEWID()),
    CHECKSUM(NEWID())
FROM dbo.Numbers AS N -- ten million rows
OPTION (MAXDOP 1);
Run Code Online (Sandbox Code Playgroud)

目标台和工作台

-- The final table we want - partitioned rowstore clustered index
CREATE TABLE [dbo].[AnalogNew]
(
    LogTime datetime2(0) NOT NULL,
    CTDID integer NOT NULL,
    WindFarmId integer NOT NULL,
    StationId integer NOT NULL,

    INDEX CCIX_Analog
        CLUSTERED (LogTime, CTDID, WindFarmId, StationId)
)
ON [AnalogMonthlyPScheme](LogTime);

-- Working table
CREATE TABLE dbo.AnalogSwitch
(
    LogTime datetime2(0) NOT NULL,
    CTDID integer NOT NULL,
    WindFarmId integer NOT NULL,
    StationId integer NOT NULL,

    INDEX CCI CLUSTERED COLUMNSTORE
);
Run Code Online (Sandbox Code Playgroud)

分区1

-- Process the first partition
ALTER TABLE dbo.Analog 
SWITCH PARTITION 1 
TO dbo.AnalogSwitch;

-- Optional, may help parallel plan
CREATE STATISTICS s ON dbo.AnalogSwitch (LogTime);

-- Convert to rowstore clustered index
CREATE CLUSTERED INDEX CCI
ON dbo.AnalogSwitch (LogTime, CTDID, WindFarmId, StationId)
WITH (DROP_EXISTING = ON);

-- Specify data range
ALTER TABLE dbo.AnalogSwitch
    ADD CONSTRAINT CK 
    CHECK (LogTime >= '20140801' AND LogTime < '20140901');

-- Move to target table
ALTER TABLE dbo.AnalogSwitch 
SWITCH TO dbo.AnalogNew 
PARTITION 1;

-- Recreate switch table
DROP TABLE dbo.AnalogSwitch;

CREATE TABLE dbo.AnalogSwitch
(
    LogTime datetime2(0) NOT NULL,
    CTDID integer NOT NULL,
    WindFarmId integer NOT NULL,
    StationId integer NOT NULL,

    INDEX CCI CLUSTERED COLUMNSTORE
);
Run Code Online (Sandbox Code Playgroud)

分区2

-- Process the second partition
ALTER TABLE dbo.Analog 
SWITCH PARTITION 2
TO dbo.AnalogSwitch;

-- Optional, may help parallel plan
CREATE STATISTICS s ON dbo.AnalogSwitch (LogTime);

-- Convert to rowstore clustered index
CREATE CLUSTERED INDEX CCI
ON dbo.AnalogSwitch (LogTime, CTDID, WindFarmId, StationId)
WITH (DROP_EXISTING = ON);

-- Specify data range
ALTER TABLE dbo.AnalogSwitch
    ADD CONSTRAINT CK 
    CHECK (LogTime >= '20140901' AND LogTime < '20141001');

-- Move to target table
ALTER TABLE dbo.AnalogSwitch 
SWITCH TO dbo.AnalogNew 
PARTITION 2;

-- Recreate switch table
DROP TABLE dbo.AnalogSwitch;

CREATE TABLE dbo.AnalogSwitch
(
    LogTime datetime2(0) NOT NULL,
    CTDID integer NOT NULL,
    WindFarmId integer NOT NULL,
    StationId integer NOT NULL,

    INDEX CCI CLUSTERED COLUMNSTORE
);
Run Code Online (Sandbox Code Playgroud)

...等等。这对脚本来说相当简单。