Sto testando inserti di registrazione minimi in diversi scenari e da quello che ho letto INSERT INTO SELECT in un heap con un indice non cluster usando TABLOCK e SQL Server 2016+ dovrebbe registrare minimamente, tuttavia nel mio caso quando sto facendo questo sto ottenendo registrazione completa. Il mio database è nel semplice modello di recupero e ottengo con successo inserimenti minimamente registrati su un heap senza indici e TABLOCK.
Sto usando un vecchio backup del database Stack Overflow per testare e ho creato una replica della tabella Posts con il seguente schema ...
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)
Provo quindi a copiare la tabella dei messaggi in questa tabella ...
INSERT INTO PostsDestination WITH(TABLOCK)
SELECT * FROM Posts ORDER BY Id
Osservando fn_dblog e l'utilizzo del file di registro, vedo che non ottengo una registrazione minima da questo. Ho letto che le versioni precedenti al 2016 richiedono il flag di traccia 610 per accedere minimamente alle tabelle indicizzate, ho anche provato a impostare questo, ma ancora senza gioia.
Immagino che mi manchi qualcosa qui?
MODIFICA - Ulteriori informazioni
Per aggiungere ulteriori informazioni sto usando la seguente procedura che ho scritto per provare a rilevare la registrazione minima, forse ho qualcosa di sbagliato qui ...
/*
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
Inserimento in un heap senza indici e TABLOCK utilizzando il seguente codice ...
EXEC sp_GetLogUseStats
@Sql = '
INSERT INTO PostsDestination
SELECT * FROM Posts ORDER BY Id ',
@Schema = 'dbo',
@Table = 'PostsDestination',
@ClearData = 1
Ottengo questi risultati
Con una crescita di file di registro di 0.0024mb, dimensioni di record di registro molto ridotte e pochissime, sono felice che questo stia utilizzando una registrazione minima.
Se poi creo un indice non cluster su id ...
CREATE INDEX ndx_PostsDestination_Id ON PostsDestination(Id)
Quindi esegui di nuovo il mio stesso inserto ...
Non solo non sto ottenendo una registrazione minima sull'indice non cluster, ma l'ho anche perso nell'heap. Dopo aver fatto qualche altro test, sembra che se creo un ID cluster, accede minimamente, ma da quello che ho letto 2016+ dovrebbe accedere minimamente a un heap con indice non cluster quando viene usato il tablock.
MODIFICA FINALE :
Ho segnalato il comportamento a Microsoft su UserVoice di SQL Server e aggiornerò se ricevo una risposta. Ho anche scritto i dettagli completi degli scenari di registro minimi che non sono riuscito a lavorare su https://gavindraper.com/2018/05/29/SQL-Server-Minimal-Logging-Inserts/