Estoy probando inserciones de registro mínimas en diferentes escenarios y, por lo que he leído, INSERTAR EN SELECCIONAR en un montón con un índice no agrupado usando TABLOCK y SQL Server 2016+ debería registrar mínimamente, sin embargo, en mi caso, al hacerlo, obtengo registro completo. Mi base de datos está en el modelo de recuperación simple y obtengo inserciones mínimamente registradas en un montón sin índices y TABLOCK.
Estoy usando una copia de seguridad antigua de la base de datos de Stack Overflow para probar y he creado una réplica de la tabla Posts con el siguiente esquema ...
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)
Luego trato de copiar la tabla de publicaciones en esta tabla ...
INSERT INTO PostsDestination WITH(TABLOCK)
SELECT * FROM Posts ORDER BY Id
Al mirar fn_dblog y el uso del archivo de registro, puedo ver que no obtengo un registro mínimo de esto. He leído que las versiones anteriores a 2016 requieren la marca de seguimiento 610 para iniciar sesión mínimamente en las tablas indexadas, también he intentado configurar esto, pero aún así no me alegro.
Supongo que me estoy perdiendo algo aquí?
EDITAR - Más información
Para agregar más información, estoy usando el siguiente procedimiento que he escrito para tratar de detectar un registro mínimo, tal vez tengo algo mal aquí ...
/*
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
Inserción en un montón sin índices y TABLOCK utilizando el siguiente código ...
EXEC sp_GetLogUseStats
@Sql = '
INSERT INTO PostsDestination
SELECT * FROM Posts ORDER BY Id ',
@Schema = 'dbo',
@Table = 'PostsDestination',
@ClearData = 1
Obtengo estos resultados
Con un crecimiento de archivo de registro de 0.0024 mb, tamaños de registro de registro muy pequeños y muy pocos de ellos, estoy feliz de que esto esté usando un registro mínimo.
Si luego creo un índice no agrupado en id ...
CREATE INDEX ndx_PostsDestination_Id ON PostsDestination(Id)
Luego ejecute mi mismo inserto nuevamente ...
No solo no obtengo un registro mínimo en el índice no agrupado, sino que también lo he perdido en el montón. Después de hacer algunas pruebas más, parece que si hago una ID agrupada, se registra mínimamente, pero por lo que he leído 2016+, debería iniciar sesión mínimamente en un montón con índice no agrupado cuando se usa tablock.
EDICION FINAL :
He informado sobre el comportamiento a Microsoft en el UserVoice de SQL Server y lo actualizaré si recibo una respuesta. También escribí todos los detalles de los escenarios de registro mínimos que no pude poner a trabajar en https://gavindraper.com/2018/05/29/SQL-Server-Minimal-Logging-Inserts/