ฉันกำลังทดสอบการแทรกการบันทึกน้อยที่สุดในสถานการณ์ที่แตกต่างกันและจากสิ่งที่ฉันอ่าน INSERT INTO SELECT เป็นฮีปที่มีดัชนีที่ไม่ใช่คลัสเตอร์โดยใช้ TABLOCK และ SQL Server 2016+ ควรบันทึกอย่างน้อยที่สุด แต่ในกรณีของฉันเมื่อทำสิ่งนี้ การบันทึกเต็มรูปแบบ ฐานข้อมูลของฉันอยู่ในรูปแบบการกู้คืนข้อมูลแบบง่ายและฉันได้รับการแทรกที่น้อยที่สุดใน heap โดยไม่มีดัชนีและ TABLOCK
ฉันใช้การสำรองข้อมูลเก่าของฐานข้อมูล Stack Overflow เพื่อทดสอบและได้สร้างการทำซ้ำของตารางโพสต์ด้วยสคีมาต่อไปนี้ ...
CREATE TABLE [dbo].[PostsDestination](
[Id] [int] NOT NULL,
[AcceptedAnswerId] [int] NULL,
[AnswerCount] [int] NULL,
[Body] [nvarchar](max) NOT NULL,
[ClosedDate] [datetime] NULL,
[CommentCount] [int] NULL,
[CommunityOwnedDate] [datetime] NULL,
[CreationDate] [datetime] NOT NULL,
[FavoriteCount] [int] NULL,
[LastActivityDate] [datetime] NOT NULL,
[LastEditDate] [datetime] NULL,
[LastEditorDisplayName] [nvarchar](40) NULL,
[LastEditorUserId] [int] NULL,
[OwnerUserId] [int] NULL,
[ParentId] [int] NULL,
[PostTypeId] [int] NOT NULL,
[Score] [int] NOT NULL,
[Tags] [nvarchar](150) NULL,
[Title] [nvarchar](250) NULL,
[ViewCount] [int] NOT NULL
)
CREATE NONCLUSTERED INDEX ndx_PostsDestination_Id ON PostsDestination(Id)
ฉันลองคัดลอกตารางการโพสต์ลงในตารางนี้ ...
INSERT INTO PostsDestination WITH(TABLOCK)
SELECT * FROM Posts ORDER BY Id
จากการดูที่ fn_dblog และการใช้งานไฟล์บันทึกฉันเห็นว่าฉันไม่ได้รับการบันทึกขั้นต่ำจากนี้ ฉันอ่านว่าเวอร์ชันก่อนปี 2559 ต้องใช้ค่าสถานะการติดตาม 610 เพื่อเข้าสู่ตารางดัชนีอย่างน้อยที่สุดฉันได้ลองตั้งค่านี้แล้ว แต่ก็ยังไม่มีความสุข
ฉันเดาว่าฉันขาดอะไรบางอย่างที่นี่?
แก้ไข - ข้อมูลเพิ่มเติม
หากต้องการเพิ่มข้อมูลเพิ่มเติมฉันใช้ขั้นตอนต่อไปนี้ที่ฉันเขียนเพื่อตรวจหาการบันทึกขั้นต่ำบางทีฉันอาจมีบางอย่างผิดปกติ ...
/*
Example Usage...
EXEC sp_GetLogUseStats
@Sql = '
INSERT INTO PostsDestination
SELECT TOP 500000 * FROM Posts ORDER BY Id ',
@Schema = 'dbo',
@Table = 'PostsDestination',
@ClearData = 1
*/
CREATE PROCEDURE [dbo].[sp_GetLogUseStats]
(
@Sql NVARCHAR(400),
@Schema NVARCHAR(20),
@Table NVARCHAR(200),
@ClearData BIT = 0
)
AS
IF @ClearData = 1
BEGIN
TRUNCATE TABLE PostsDestination
END
/*Checkpoint to clear log (Assuming Simple/Bulk Recovery Model*/
CHECKPOINT
/*Snapshot of logsize before query*/
CREATE TABLE #BeforeLogUsed(
[Db] NVARCHAR(100),
LogSize NVARCHAR(30),
Used NVARCHAR(50),
Status INT
)
INSERT INTO #BeforeLogUsed
EXEC('DBCC SQLPERF(logspace)')
/*Run Query*/
EXECUTE sp_executesql @SQL
/*Snapshot of logsize after query*/
CREATE TABLE #AfterLLogUsed(
[Db] NVARCHAR(100),
LogSize NVARCHAR(30),
Used NVARCHAR(50),
Status INT
)
INSERT INTO #AfterLLogUsed
EXEC('DBCC SQLPERF(logspace)')
/*Return before and after log size*/
SELECT
CAST(#AfterLLogUsed.Used AS DECIMAL(12,4)) - CAST(#BeforeLogUsed.Used AS DECIMAL(12,4)) AS LogSpaceUsersByInsert
FROM
#BeforeLogUsed
LEFT JOIN #AfterLLogUsed ON #AfterLLogUsed.Db = #BeforeLogUsed.Db
WHERE
#BeforeLogUsed.Db = DB_NAME()
/*Get list of affected indexes from insert query*/
SELECT
@Schema + '.' + so.name + '.' + si.name AS IndexName
INTO
#IndexNames
FROM
sys.indexes si
JOIN sys.objects so ON si.[object_id] = so.[object_id]
WHERE
si.name IS NOT NULL
AND so.name = @Table
/*Insert Record For Heap*/
INSERT INTO #IndexNames VALUES(@Schema + '.' + @Table)
/*Get log recrod sizes for heap and/or any indexes*/
SELECT
AllocUnitName,
[operation],
AVG([log record length]) AvgLogLength,
SUM([log record length]) TotalLogLength,
COUNT(*) Count
INTO #LogBreakdown
FROM
fn_dblog(null, null) fn
INNER JOIN #IndexNames ON #IndexNames.IndexName = allocunitname
GROUP BY
[Operation], AllocUnitName
ORDER BY AllocUnitName, operation
SELECT * FROM #LogBreakdown
SELECT AllocUnitName, SUM(TotalLogLength) TotalLogRecordLength
FROM #LogBreakdown
GROUP BY AllocUnitName
แทรกลงในกองที่ไม่มีดัชนีและ TABLOCK โดยใช้รหัสต่อไปนี้ ...
EXEC sp_GetLogUseStats
@Sql = '
INSERT INTO PostsDestination
SELECT * FROM Posts ORDER BY Id ',
@Schema = 'dbo',
@Table = 'PostsDestination',
@ClearData = 1
ฉันได้รับผลลัพธ์เหล่านี้
ที่การเติบโตของแฟ้มบันทึก 0.0024mb ขนาดของบันทึกที่มีขนาดเล็กมากและน้อยมากที่พวกเขาดีใจที่ใช้การบันทึกที่น้อยที่สุด
ถ้าฉันสร้างดัชนีที่ไม่ใช่คลัสเตอร์บน id ...
CREATE INDEX ndx_PostsDestination_Id ON PostsDestination(Id)
จากนั้นเรียกใช้ส่วนแทรกเดิมของฉันอีกครั้ง ...
ไม่เพียง แต่ฉันจะไม่ได้รับการบันทึกขั้นต่ำในดัชนีที่ไม่ใช่แบบคลัสเตอร์ แต่ฉันได้สูญเสียมันไปในฮีปด้วย หลังจากทำการทดสอบเพิ่มเติมดูเหมือนว่าถ้าฉันทำ ID คลัสเตอร์มันจะล็อกน้อยที่สุด แต่จากสิ่งที่ฉันอ่าน 2016+ ควรล็อกฮีปที่มีดัชนีที่ไม่ได้คลัสเตอร์น้อยที่สุดเมื่อใช้ tablock
แก้ไขครั้งสุดท้าย :
ฉันได้รายงานพฤติกรรมไปยัง Microsoft ในSQL Server UserVoiceและจะอัปเดตหากฉันได้รับคำตอบ ผมเคยเขียนถึงรายละเอียดทั้งหมดของสถานการณ์เข้าสู่ระบบน้อยที่สุดที่ฉันไม่สามารถได้รับการทำงานที่https://gavindraper.com/2018/05/29/SQL-Server-Minimal-Logging-Inserts/