我们有以下架构
临时表是从外部数据库直接加载的,每周一次,临时表中的数据会加载到读取表中,并有一些内部联接,以减少用户点击读取表时的读取次数。问题是临时表中的数据量足够大,以至于超出了我们的数据库日志,因此我们被要求实施批处理。
我有下面的脚本,它可以工作,但到目前为止它只运行我们需要迁移的数据的 1/8,并且运行大约需要 4 小时。暂存表中的记录量约为 8000 万条记录,表 2 约为 400 条记录(带索引、唯一值和应用的 PK)。
DECLARE @PageSize int = 50000;
DECLARE @PageIndex int = 0;
DECLARE @TotalPages int = 0;
SELECT @TotalPages = ((count(1) / @PageSize) + 1)
FROM Table1_Staging t1
INNER JOIN Table2 t2 ON t2.r1 = t1.r7
INNER JOIN Table2 t3 ON t3.r1 = t1.r8
SELECT @TotalPages;
WHILE (@PageIndex <= @TotalPages)
BEGIN
BEGIN TRANSACTION
INSERT INTO Table1 ( [row1], [row2], [row3], [row4],
[row5], [row6], [row7], [row8])
SELECT t1.r2,
t1.r3,
t2.r1,
t2.r3,
t3.r3,
t1.r6,
IIF(TRY_CONVERT(datetime, t1.DATE) IS NULL,
DATEADD(YEAR, -1, GETDATE()),
TRY_CONVERT(datetime, t1.DATE))
AS date,
t1.r1
FROM Table1_Staging t1
INNER JOIN Table2 t2 ON t2.r1 = t1.r7
INNER JOIN Table2 t3 ON t3.r1 = t1.r8
ORDER BY t1.r2 DESC
OFFSET (@PageSize * @PageIndex) ROWS
FETCH NEXT @PageSize ROWS ONLY;
COMMIT TRANSACTION;
/** Increments the Page Size */
SET @PageIndex = @PageIndex + 1;
END
有人对优化此查询或仅在 SQL 中批量加载数据的不同方式有任何建议吗?应用于所有表的索引和 PK 已针对查询进行了优化。或者我应该将 PageSize 增加到像 500,000 这样的大值。
我们最终进行的优化如下: 在临时表上添加 IDENTITY INT 主键,删除行号分页并使用 KEYSET 分页。将 4 小时的查询缩短至约 22 分钟。
DECLARE @PageSizeCurrent int = 0;
DECLARE @PageSizeIncrement int = 50000;
DECLARE @rowCount int = 1;
WHILE (@rowCount > 0)
BEGIN
BEGIN TRANSACTION
INSERT INTO Table1 ([row1], [row2], [row3], [row4],
[row5], [row6], [row7], [row8])
SELECT
t1.r2, t1.r3, t2.r1, t2.r3,
t3.r3, t1.r6,
IIF(TRY_CONVERT(datetime, t1.DATE) IS NULL, DATEADD(YEAR, -1,
GETDATE()),
TRY_CONVERT(datetime, t1.DATE)) AS date,
t1.r1
FROM
Table1_Staging t1
INNER JOIN
Table2 t2 ON t2.r1 = t1.r7
INNER JOIN
Table2 t3 ON t3.r1 = t1.r8
WHERE t1.[id] > @PageSize AND t1.[id] < (@PageSize + @PageSizeIncrement)
SET @rowCount = @@ROWCOUNT
COMMIT TRANSACTION;
/** Increments the Page Size */
SET @PageSize = @PageSize + @PageSizeIncrement;
END