9 sql-server-2008 sql-server bulk-insert
我已经编写了一个脚本来测试在这个页面http://technet.microsoft.com/en-us/library/dd425070(v=sql.100).aspx中标题为 Summarizing Minimal Logging conditions about when最小日志记录发生或不发生。
使用此脚本,我发现每种不同类型插入的日志记录长度总和如下:
其中一些数字似乎与 technet 页面上的表格不符。特别是:
作为参考,这是在 SQL express 数据库上运行的,当我运行 DBCC TRACESTATUS (610) 时,一切都是 0。
任何人都可以帮助解释为什么我可能会看到这些差异?
参考代码如下:
SET NOCOUNT ON
CREATE TABLE numbers (num INT)
CREATE TABLE numbersUnordered (num INT)
Declare @cnt int
Select @cnt=0
while (@cnt<500)
BEGIN
INSERT INTO NUMBERS(num) SELECT @cnt
SELECT @cnt=@cnt+1
END
Select @cnt=0
while (@cnt<250)
BEGIN
INSERT INTO numbersUnordered(num) SELECT @cnt*2
SELECT @cnt=@cnt+1
END
Select @cnt=0
while (@cnt<250)
BEGIN
INSERT INTO numbersUnordered(num) SELECT @cnt*2+1
SELECT @cnt=@cnt+1
END
---- heap empty without tablock
CREATE TABLE noKey1 (val INT)
INSERT INTO noKey1 (val)
SELECT * FROM numbers
DECLARE @heapEmptyNoTablock INT
SELECT @heapEmptyNoTablock = SUM([Log Record Length])
FROM sys.fn_dblog(null, null)
WHERE allocunitname like '%noKey1%'
AND operation like '%insert%'
---- heap empty with tablock
CREATE TABLE noKey2 (val INT)
INSERT INTO noKey2 WITH(TABLOCK) (val)
SELECT * FROM numbers
DECLARE @heapEmptyTablock INT
SELECT @heapEmptyTablock = SUM([Log Record Length])
FROM sys.fn_dblog(null, null)
WHERE allocunitname like '%noKey2%'
AND operation like '%insert%'
---- heap non empty without tablock
CREATE TABLE noKey3 (val INT)
INSERT INTO noKey3 WITH(TABLOCK) (val)
SELECT * FROM numbers
INSERT INTO noKey3 (val)
SELECT num+5 FROM numbers
DECLARE @heapNonEmptyNoTablock INT
SELECT @heapNonEmptyNoTablock = SUM(a.[Log Record Length])
FROM
(SELECT TOP 500 * FROM sys.fn_dblog(null, null)
WHERE allocunitname like '%noKey3%'
AND operation like '%insert%'
ORDER BY [Current LSN] desc) a
---- heap non empty with tablock
CREATE TABLE noKey4 (val INT)
INSERT INTO noKey4 WITH(TABLOCK) (val)
SELECT * FROM numbers
INSERT INTO noKey4 WITH (TABLOCK) (val)
SELECT num+5 FROM numbers
DECLARE @heapNonEmptyTablock INT
SELECT @heapNonEmptyTablock = SUM(a.[Log Record Length])
FROM
(SELECT TOP 500 * FROM sys.fn_dblog(null, null)
WHERE allocunitname like '%noKey4%'
AND operation like '%insert%'
ORDER BY [Current LSN] desc) a
--- heap plus index empty without tablock
CREATE TABLE noKey5 (val INT)
CREATE INDEX MSindex1
ON noKey5 (val)
INSERT INTO noKey5 (val)
SELECT * FROM numbers
DECLARE @heapIndexEmptyNoTablock INT
SELECT @heapIndexEmptyNoTablock = SUM([Log Record Length])
FROM sys.fn_dblog(null, null)
WHERE allocunitname like '%noKey5%'
AND operation like '%insert%'
--- heap plus index empty with tablock
CREATE TABLE noKey6 (val INT)
CREATE INDEX MSindex2
ON noKey6 (val)
INSERT INTO noKey6 WITH(TABLOCK) (val)
SELECT * FROM numbers
DECLARE @heapIndexEmptyTablock INT
SELECT @heapIndexEmptyTablock = SUM([Log Record Length])
FROM sys.fn_dblog(null, null)
WHERE allocunitname like '%noKey6%'
AND operation like '%insert%'
--- heap plus index non empty without tablock
CREATE TABLE noKey7 (val INT)
CREATE INDEX MSindex3
ON noKey7 (val)
INSERT INTO noKey7 WITH(TABLOCK) (val)
SELECT * FROM numbers
INSERT INTO noKey7 (val)
SELECT num+5 FROM numbers
DECLARE @heapIndexNonEmptyNoTablock INT
SELECT @heapIndexNonEmptyNoTablock = SUM(a.[Log Record Length])
FROM
(SELECT TOP 1000 * FROM sys.fn_dblog(null, null)
WHERE allocunitname like '%noKey7%'
AND operation like '%insert%'
ORDER BY [Current LSN] desc) a
--- heap plus index non empty with tablock
CREATE TABLE noKey8 (val INT)
CREATE INDEX MSindex4
ON noKey7 (val)
INSERT INTO noKey8 WITH(TABLOCK) (val)
SELECT * FROM numbers
INSERT INTO noKey8 WITH(TABLOCK) (val)
SELECT num+5 FROM numbers
DECLARE @heapIndexNonEmptyTablock INT
SELECT @heapIndexNonEmptyTablock = SUM(a.[Log Record Length])
FROM
(SELECT TOP 1000 * FROM sys.fn_dblog(null, null)
WHERE allocunitname like '%noKey8%'
AND operation like '%insert%'
ORDER BY [Current LSN] desc) a
--- cluster empty ordered without tablock
CREATE TABLE withKey1 (val INT PRIMARY KEY)
INSERT INTO withKey1 (val)
SELECT * FROM numbers
DECLARE @clusterEmptyNoTablock INT
SELECT @clusterEmptyNoTablock = SUM([Log Record Length])
FROM sys.fn_dblog(null, null)
WHERE allocunitname like '%withKey1%'
AND operation like '%insert%'
--- cluster empty ordered with tablock
CREATE TABLE withKey2 (val INT PRIMARY KEY)
INSERT INTO withKey2 WITH(TABLOCK) (val)
SELECT * FROM numbers
DECLARE @clusterEmptyTablock INT
SELECT @clusterEmptyTablock = SUM([Log Record Length])
FROM sys.fn_dblog(null, null)
WHERE allocunitname like '%withKey2%'
AND operation like '%insert%'
--- cluster empty unordered without tablock
CREATE TABLE withKey5 (val INT PRIMARY KEY)
INSERT INTO withKey5 (val)
SELECT * FROM numbersUnordered
DECLARE @clusterEmptyNoTablockUnordered INT
SELECT @clusterEmptyNoTablockUnordered = SUM([Log Record Length])
FROM sys.fn_dblog(null, null)
WHERE allocunitname like '%withKey5%'
AND operation like '%insert%'
--- cluster empty undordered with tablock
CREATE TABLE withKey6 (val INT PRIMARY KEY)
INSERT INTO withKey6 WITH(TABLOCK) (val)
SELECT * FROM numbersUnordered
DECLARE @clusterEmptyTablockUnordered INT
SELECT @clusterEmptyTablockUnordered = SUM([Log Record Length])
FROM sys.fn_dblog(null, null)
WHERE allocunitname like '%withKey6%'
AND operation like '%insert%'
--- cluster non empty no tablock
CREATE TABLE withKey7 (val INT PRIMARY KEY)
INSERT INTO withKey7 (val)
SELECT num FROM numbers
INSERT INTO withKey7 (val)
SELECT num+500 FROM numbers
DECLARE @clusterNonEmptyNoTablock INT
SELECT @clusterNonEmptyNoTablock = SUM(a.[Log Record Length])
FROM
(SELECT TOP 500 * FROM sys.fn_dblog(null, null)
WHERE allocunitname like '%withKey7%'
AND operation like '%insert%'
ORDER BY [Current LSN] desc) a
--- cluster non empty with tablock
CREATE TABLE withKey8 (val INT PRIMARY KEY)
INSERT INTO withKey8 WITH(TABLOCK) (val)
SELECT num FROM numbers
INSERT INTO withKey8 WITH(TABLOCK) (val)
SELECT num+500 FROM numbers
DECLARE @clusterNonEmptyTablock INT
SELECT @clusterNonEmptyTablock = SUM(a.[Log Record Length])
FROM
(SELECT TOP 500 * FROM sys.fn_dblog(null, null)
WHERE allocunitname like '%withKey8%'
AND operation like '%insert%'
ORDER BY [Current LSN] desc) a
--- cluster plus index empty no tablock
CREATE TABLE withKey9 (val INT PRIMARY KEY)
CREATE INDEX MSindex5
ON withKey9 (val)
INSERT INTO withKey9 (val)
SELECT * FROM numbers
DECLARE @clusterIndexEmptyNoTablock INT
SELECT @clusterIndexEmptyNoTablock = SUM([Log Record Length])
FROM sys.fn_dblog(null, null)
WHERE allocunitname like '%withKey9%'
AND operation like '%insert%'
--- cluster plus index empty with tablock
CREATE TABLE withKey10 (val INT PRIMARY KEY)
CREATE INDEX MSindex6
ON withKey10 (val)
INSERT INTO withKey10 WITH(TABLOCK) (val)
SELECT * FROM numbers
DECLARE @clusterIndexEmptyTablock INT
SELECT @clusterIndexEmptyTablock = SUM([Log Record Length])
FROM sys.fn_dblog(null, null)
WHERE allocunitname like '%withKey10%'
AND operation like '%insert%'
--- cluster plus index nonempty no tablock
CREATE TABLE withKey11 (val INT PRIMARY KEY)
CREATE INDEX MSindex7
ON withKey11 (val)
INSERT INTO withKey11 (val)
SELECT num FROM numbers
INSERT INTO withKey11 (val)
SELECT num+500 FROM numbers
DECLARE @clusterIndexNonEmptyNoTablock INT
SELECT @clusterIndexNonEmptyNoTablock = SUM(a.[Log Record Length])
FROM
(SELECT TOP 1000 * FROM sys.fn_dblog(null, null)
WHERE allocunitname like '%withKey11%'
AND operation like '%insert%'
ORDER BY [Current LSN] desc) a
--- cluster plus index nonempty with tablock
CREATE TABLE withKey12 (val INT PRIMARY KEY)
CREATE INDEX MSindex8
ON withKey12 (val)
INSERT INTO withKey12 WITH(TABLOCK) (val)
SELECT num FROM numbers
INSERT INTO withKey12 WITH(TABLOCK) (val)
SELECT num+500 FROM numbers
DECLARE @clusterIndexNonEmptyTablock INT
SELECT @clusterIndexNonEmptyTablock = SUM(a.[Log Record Length])
FROM
(SELECT TOP 1000 * FROM sys.fn_dblog(null, null)
WHERE allocunitname like '%withKey12%'
AND operation like '%insert%'
ORDER BY [Current LSN] desc) a
--- select into
/*SELECT *
INTO selectIntoTable
FROM numbers
SELECT * FROM sys.fn_dblog(null, null)
WHERE allocunitname like '%selectIntoTable%'
AND operation like '%insert%'
DROP TABLE selectIntoTable
*/
PRINT 'Heap empty no tablock ' + CAST(@heapEmptyNoTablock AS VARCHAR)
PRINT 'Heap empty with tablock ' + CAST(@heapEmptyTablock AS VARCHAR)
PRINT 'Heap non empty no tablock ' + CAST(@heapNonEmptyNoTablock AS VARCHAR)
PRINT 'Heap non empty with tablock ' + CAST(@heapNonEmptyTablock AS VARCHAR)
PRINT 'Heap plus index empty no tablock ' + CAST(@heapIndexEmptyNoTablock AS VARCHAR)
PRINT 'Heap plus index empty with tablock ' + CAST(@heapIndexEmptyTablock AS VARCHAR)
PRINT 'Heap plus index non empty no tablock ' + CAST(@heapIndexNonEmptyNoTablock AS VARCHAR)
PRINT 'Heap plus index non empty with tablock ' + CAST(@heapIndexNonEmptyTablock AS VARCHAR)
PRINT 'Cluster empty ordered no tablock ' + CAST(@clusterEmptyNoTablock AS VARCHAR)
PRINT 'Cluster empty ordered with tablock ' + CAST(@clusterEmptyTablock AS VARCHAR)
PRINT 'Cluster empty unordered no tablock ' + CAST(@clusterEmptyNoTablockUnordered AS VARCHAR)
PRINT 'Cluster empty unordered with tablock ' + CAST(@clusterEmptyTablockUnordered AS VARCHAR)
PRINT 'Cluster non empty no tablock ' + CAST(@clusterNonEmptyNoTablock AS VARCHAR)
PRINT 'Cluster non empty with tablock ' + CAST(@clusterNonEmptyTablock AS VARCHAR)
PRINT 'Cluster plus index empty no tablock ' + CAST(@clusterIndexEmptyNoTablock AS VARCHAR)
PRINT 'Cluster plus index empty with tablock ' + CAST(@clusterIndexEmptyTablock AS VARCHAR)
PRINT 'Cluster plus index non empty no tablock ' + CAST(@clusterIndexNonEmptyNoTablock AS VARCHAR)
PRINT 'Cluster plus index non empty with tablock ' + CAST(@clusterIndexNonEmptyTablock AS VARCHAR)
DROP TABLE numbers
DROP TABLE numbersUnordered
DROP TABLE noKey1
DROP TABLE noKey2
DROP TABLE noKey3
DROP TABLE noKey4
DROP TABLE noKey5
DROP TABLE noKey6
DROP TABLE noKey7
DROP TABLE noKey8
DROP TABLE withKey1
DROP TABLE withKey2
DROP TABLE withKey5
DROP TABLE withKey6
DROP TABLE withKey7
DROP TABLE withKey8
DROP TABLE withKey9
DROP TABLE withKey10
DROP TABLE withKey11
DROP TABLE withKey12
Run Code Online (Sandbox Code Playgroud)
Pau*_*ite 13
其中一些数字似乎与 technet 页面上的表格不符。
测试中生成的日志记录的大小存在细微差异,但这是由于其他内部日志记录行为造成的,而不是是否发生了最小日志记录。
存储引擎团队的 Sunil Agarwal 提供了最小日志记录的一个很好的定义:
不记录单个行,仅记录对页面分配结构的更改
您看到记录的单个行更改(例如LOP_INSERT_ROWS)的任何测试都没有对关联的分配单元使用最少的日志记录。某些操作可以针对一个分配单元(例如索引)进行最低限度的记录,而不是针对另一个进行最低限度的记录。此外,在某些情况下,对现有页面的插入可能不会被最少记录,但对新分配的页面的更改可能会被记录。
大多数细节可以在一系列存储引擎团队博客文章中找到:
那里没有探讨的一个细节是,要最少记录(在 SQL Server 2008 或更高版本中)INSERT...SELECT对 b 树结构的更改必须将DMLRequestSort查询计划运算符属性设置为 true。这适用于数据加载性能指南显示“取决于”的情况:查询计划必须使用广泛(每个索引)维护和DMLRequestSort=true.
我在Minimal Logging with INSERT…SELECT 和 Fast Load Context 中写了更多关于这个的内容。
| 归档时间: |
|
| 查看次数: |
946 次 |
| 最近记录: |