Điều kiện ghi nhật ký tối thiểu trong SQL


9

Tôi đã viết một tập lệnh để kiểm tra các khiếu nại được đưa ra trên trang này http://technet.microsoft.com/en-us/l Library / dd425070 (v = sql.100) .aspx trong bảng có tiêu đề Tóm tắt các điều kiện ghi nhật ký tối thiểu về thời điểm đăng nhập tối thiểu không hoặc không xảy ra.

Sử dụng tập lệnh này tôi thấy rằng tổng của Độ dài bản ghi nhật ký cho từng loại chèn khác nhau là như sau:

  • Heap trống không có tablock 60000
  • Heap trống với tablock 56000
  • Heap không trống không có khóa 60000
  • Heap không trống với tablock 56000
  • Heap plus index trống không có tablock 126188
  • Heap plus index trống với tablock 114188
  • Heap plus index không trống không có tablock 138696
  • Heap plus index không trống với tablock 112000
  • Cụm trống được đặt hàng không có tablock 64168
  • Cụm trống được đặt hàng với tablock 56168
  • Cụm trống không có thứ tự không có tablock 73388
  • Cụm trống không có thứ tự với tablock 65388
  • Cụm không trống không có khóa tab 63912
  • Cụm không trống với tablock 55944
  • Cụm cộng chỉ số trống không có tablock 124336
  • Cụm cộng chỉ mục trống với tablock 108336
  • Cụm cộng chỉ mục không trống không có tablock 123876
  • Cụm cộng chỉ mục không trống với tablock 107924

Một vài trong số những con số này dường như không khớp với bảng trên trang kỹ thuật. Đặc biệt:

  • Dường như không có sự khác biệt trong việc ghi nhật ký giữa việc chèn vào các bảng trống so với các bảng trống, nhưng trang tuyên bố rằng cần phải ghi nhật ký đầy đủ khi chèn vào một cụm không trống mà không có khóa tab
  • Chèn với khóa tab vào một đống hoặc cụm với và chỉ mục dường như làm giảm việc ghi nhật ký, nhưng trang tuyên bố rằng cần phải ghi nhật ký đầy đủ.
  • Khi sử dụng phương thức chèn CHỌN VÀO, không có hàng nào trong fn_dblog có thao tác được chèn, nhưng trang liệt kê phương thức này là hoạt động tải hàng loạt nên có hành vi được mô tả trong bảng

Để tham khảo, điều này đã được chạy trên cơ sở dữ liệu SQL express và khi tôi chạy DBCC TRACESTATUS (610), mọi thứ đều bằng 0.

Bất cứ ai có thể giúp giải thích lý do tại sao tôi có thể nhìn thấy những khác biệt này?

Để tham khảo mã dưới đây:

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

Câu trả lời:


12

Một vài trong số những con số này dường như không khớp với bảng trên trang kỹ thuật.

Có sự khác biệt nhỏ về kích thước của các bản ghi nhật ký được tạo trong các thử nghiệm của bạn, nhưng những điều này là do các hành vi ghi nhật ký nội bộ khác, không phải là việc ghi nhật ký tối thiểu có xảy ra hay không.

Một định nghĩa tốt về ghi nhật ký tối thiểu được cung cấp bởi Sunil Agarwal của nhóm Storage Engine:

Các hàng riêng lẻ không được ghi lạichỉ những thay đổi đối với cấu trúc phân bổ trang được ghi lại

Bất kỳ thử nghiệm nào bạn thấy các thay đổi hàng riêng lẻ được ghi lại (ví dụ LOP_INSERT_ROWS) không sử dụng ghi nhật ký tối thiểu cho đơn vị phân bổ được liên kết. Một số hoạt động có thể được ghi lại tối thiểu đối với một đơn vị phân bổ (ví dụ: một chỉ mục) và không được ghi lại tối thiểu so với đơn vị khác. Ngoài ra, trong một số trường hợp, việc chèn vào các trang hiện tại có thể không được ghi lại tối thiểu nhưng có thể thay đổi trang mới được phân bổ.

Hầu hết các chi tiết có thể được tìm thấy trong một loạt các bài đăng trên blog của nhóm Storage Engine:

Một chi tiết chưa được khám phá đó là để được ghi nhật ký tối thiểu (trong SQL Server 2008 trở lên) INSERT...SELECTthay đổi cấu trúc cây b phải có thuộc DMLRequestSorttính toán tử kế hoạch truy vấn được đặt thành đúng. Điều này áp dụng cho các trường hợp trong đó Hướng dẫn hiệu suất tải dữ liệu hiển thị 'Tùy thuộc': gói truy vấn phải sử dụng bảo trì rộng (trên mỗi chỉ mục) DMLRequestSort=true.

Tôi đã viết thêm về điều này trong Ghi nhật ký tối thiểu với BERTNG CHỌN LỰA CHỌN và Bối cảnh tải nhanh .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.