Problema clave ascendente: columna principal con la marca "Estacionaria" - SQL Server

9

He estado investigando consultas de ejecución lenta en nuestra base de datos y he llegado a la conclusión de que este es un problema clásico de clave ascendente. A medida que se insertan nuevas filas casi constantemente, y una parte determinada de SQL para extraer los datos más recientes de la base de datos se ejecuta cada 30 minutos, la primera opción de actualizar las estadísticas cada 30 minutos parecía que podría ser un desperdicio de recursos.

Entonces, busqué en Trace Flag 2389, que en principio debería ayudar, sin embargo, eso requiere que la columna Líder se marque como Ascendente, y cuando utilicé Trace Flag 2388 para verificar las estadísticas del índice (PK), veo que la columna principal es en realidad calificado como estacionario, como lo es para varios de los índices PK en otras tablas actualizadas al mismo tiempo.

ingrese la descripción de la imagen aquí

No parece haber mucha orientación sobre lo que resulta en una marca de Stationary, sin embargo, encontré KB2952101 que dice que si menos del 90% de los insertos eran mayores que el valor máximo anterior, se clasificaría como Stationary. Todas nuestras inserciones son presentaciones nuevas, y la columna inicial es una columna de IDENTIDAD bigint, por lo que el 100% de las inserciones deben ser mayores que el valor máximo anterior.

Entonces, mi pregunta es ¿por qué la columna se marcaría como Estacionaria, cuando obviamente es Ascendente?

Un intento anterior de resolver este problema para algunos SQL que se ejecutan diariamente (que funcionó realmente bien) dio como resultado que se configurara un trabajo para actualizar las estadísticas de esta tabla todas las noches. La actualización no realiza un ESCANEO COMPLETO, entonces, ¿podría ser que el escaneo muestreado falte algunas veces en las nuevas filas, por lo que no siempre se muestra como ascendente?

La única otra cosa que puedo pensar que podría afectar esto es que tenemos un trabajo de archivo que se ejecuta detrás de escena eliminando filas durante una cierta edad. ¿Podría esto tener un efecto en la marca?

El servidor es SQL Server 2012 SP1.

Actualización : otro día, otra actualización de estadísticas: la misma marca estacionaria. Ha habido 28049 nuevas inserciones desde la actualización de estadísticas anterior. Cada fila tiene una marca de tiempo de cuando se insertó, por lo que si selecciono max (id) de la tabla donde la marca de tiempo <'20161102' obtengo 23313455 Del mismo modo, si hago eso para cuando las estadísticas se actualizaron hoy, obtengo 23341504.

La diferencia entre estos radica en las nuevas inserciones 28049, por lo que, como puede ver, a todas las nuevas inserciones se les dieron nuevas claves ascendentes (como se esperaba), lo que sugiere que la columna principal debe marcarse como ascendente en lugar de estacionaria.

Durante el mismo período, nuestro trabajo de archivo eliminó 213,629 filas (estamos borrando lentamente los datos antiguos). ¿Hay alguna posibilidad de que un número reducido de filas pueda contribuir a la marca estacionaria? He probado esto antes y no parecía que hubiera ninguna diferencia.

Actualización 2 : ¡Otro día, otra actualización de estadísticas, y la columna ahora está marcada como Ascendente! De acuerdo con la teoría sobre las eliminaciones que afectan esto, verifiqué el porcentaje de actualizaciones que se insertan en comparación con las eliminaciones, y ayer el 13% fueron inserciones, mientras que las inserciones de los dos días anteriores representaron aproximadamente el 12%. No creo que eso nos dé nada concluyente.

Curiosamente, una tabla relacionada que obtiene un promedio de 4 filas insertadas para cada fila insertada en esta tabla principal, y tiene sus estadísticas actualizadas al mismo tiempo, ¿tiene su columna PK IDENTIDAD como estacionaria?

Actualización 3 : durante el fin de semana tenemos más inserciones. Esta mañana, la columna principal vuelve a Estacionaria. En la última actualización de estadísticas, tuvimos 46840 inserciones y solo 34776 eliminaciones.

De nuevo, curiosamente, la tabla relacionada que mencioné anteriormente ahora tiene su columna principal marcada como Ascendente. ¿No hay documentación que pueda explicar esto?

Actualización 4 : ha pasado una semana más o menos, el trabajo de archivado ha borrado el trabajo atrasado, por lo que estamos eliminando constantemente alrededor de dos tercios del número de filas que se insertan. Las estadísticas muestran resultados mixtos en las tablas relacionadas, una muestra estacionaria y dos ascendentes, a pesar de que todas se actualizan proporcionalmente de manera similar.

Nik
fuente
En nuestro caso, todas las inserciones tienen valores que están más allá del valor más alto en el histograma, por lo que la columna no debe tener la marca Estacionaria, por lo que no he probado la bandera. Es una explicación de por qué SQL Server parece marcar aleatoriamente las columnas que realmente busco. Gracias.
Nik

Respuestas:

3

No parece haber mucha orientación sobre lo que resulta en una marca de Stationary, sin embargo, encontré KB2952101 que dice que si menos del 90% de los insertos eran mayores que el valor máximo anterior, se clasificaría como Stationary. Todas nuestras inserciones son presentaciones nuevas, y la columna inicial es una columna IDENTIDAD bigint, por lo que el 100% de las inserciones deben ser mayores que el valor máximo anterior.

Entonces, mi pregunta es ¿por qué la columna se marcaría como Estacionaria, cuando obviamente es Ascendente?

Se marcará estacionario si, como ya ha dicho, que el 10% o más de los insertos no son ascendentes. Si el 100% de sus inserciones fueran como usted dice ... entonces es posible que no tenga este problema, hasta que, por supuesto, lo elimine, pero luego volvería a ser desconocido.

Aquí hay una reproducción de su problema:

use master;
go
-- create a database for this to test
create database AscendingKey;
go

use AscendingKey;
go
-- create a test table
create table dbo.AscendingKeyTableTest
(
    SomeData        char(100) default('A'),
    AscendingKey    bigint not null,
);
go

-- insert some dummy data
set nocount on
go

declare @i int = 1

while(@i <= 1000)
begin
    insert into AscendingKeyTableTest(AscendingKey) VALUES (@i);
    set @i += 1
end
go

-- create stats on the ascendingkey column
create statistics AscendingKeyStats on dbo.AscendingKeyTableTest(AscendingKey);
go

-- look at the stats
dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
-- unknown

-- now insert a few more ascending
declare @i int;
declare @j int = 1;

SELECT @i = max(ascendingkey) from dbo.AscendingKeyTableTest;

while(@j <= 10)
begin
    insert into AscendingKeyTableTest(AscendingKey) VALUES (@i+@j);
    set @j += 1
end
go

-- check again
dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
-- unknown

-- update the stats
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;

-- now insert a few more ascending
declare @i int;
declare @j int = 1;

SELECT @i = max(ascendingkey) from dbo.AscendingKeyTableTest;

while(@j <= 10)
begin
    insert into AscendingKeyTableTest(AscendingKey) VALUES (@i+@j);
    set @j += 1
end
go

-- update the stats
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;

-- check again
dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);

-- now insert a few more ascending
declare @i int;
declare @j int = 1;

SELECT @i = max(ascendingkey) from dbo.AscendingKeyTableTest;

while(@j <= 10)
begin
    insert into AscendingKeyTableTest(AscendingKey) VALUES (@i+@j);
    set @j += 1
end
go

-- update the stats
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;

-- check again
dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
-- ascending!
-- we hit the 3x stats updates to have it 'learn'

-- what happens if we insert more than 10% that isn't ascending
declare @i int = 1;

while(@i <= 10)
begin
    insert into AscendingKeyTableTest(AscendingKey) VALUES (@i);
    set @i += 1
end
go

-- still says ascending... but...
dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
go
-- what if we update again?
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;
go
-- stationary
dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
go
-- get it back to ascending
declare @i int;

SELECT @i = max(ascendingkey) from dbo.AscendingKeyTableTest;

insert into AscendingKeyTableTest(AscendingKey) VALUES (@i+1);
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;

insert into AscendingKeyTableTest(AscendingKey) VALUES (@i+2);
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;

insert into AscendingKeyTableTest(AscendingKey) VALUES (@i+3);
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;
go

dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
go

-- what about the deletes?
delete from AscendingKeyTableTest where AscendingKey % 3 = 0
go

update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;
go

dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
go
-- back to unknown

-- cleanup
use master
go

drop database AscendingKey
go
Sean Gallardy - Usuario retirado
fuente
Hice una prueba rápida con el mismo script que el anterior, pero solo ejecuté las partes de inserción y eliminación. Parece que si elimina una cantidad mucho mayor de filas de las insertadas, volverá a estar estacionaria (nuevamente alrededor del 10%). En sus datos actualizados, ha insertado aproximadamente el 10% de todos los cambios de datos realizados, parece que las eliminaciones le causan dolor. En este punto, sugeriría dejar que el objeto de estadísticas golpee ascendente y luego congelarlo al no actualizarlo.
Sean Gallardy - Usuario retirado el
Intenté recrear lo que había hecho, y terminé agregando 10 filas más y eliminando 1000, actualizando estadísticas, luego mostrando estadísticas, y todavía se muestra como ascendente: Inserciones desde la última actualización: 10, Elimina desde la última actualización: 1000, Tipo de columna inicial : Ascendente. ¿No está seguro de por qué obtengo un resultado diferente para usted? Si sus hallazgos son correctos, puede ser solo un caso de aguantar resultados menos que óptimos ahora, luego, cuando se haya despejado nuestro retraso en el archivo, intente nuevamente.
Nik
0

En mi opinión, a menos que esté generando la columna de clave principal en el servidor, puede meterse en pequeños baches confiando en que se genere en clientes individuales.

Además, ¿has probado Trace Flag 2371?

TF 2371 se documenta aquí .

El KB se titula "Control del comportamiento de Autostat (AUTO_UPDATE_STATISTICS) en SQL Server". y el KB es 2754171.

Sería muy útil si nos hiciera una lista de los impactos reales de los nuevos datos que no llegan a las estadísticas a tiempo.

Se eligieron los índices incorrectos. Y, si es así, ¿puede enumerarnos los índices y sus claves principales?

Además, ¿puede compartir los planes que se generan cuando las estadísticas están fechadas cuando son oportunas? Me gustaría comparar los dos.

Mi opinión es que las decisiones de SQL Cost Based Optimizer (reglas y costos) son bastante buenas; fuera de áreas esotéricas como esta.

Si este es un caso especial, puede ser útil más explicación y justificar la apertura de un elemento de conexión.

Además, en mi humilde opinión, tendrá mayores beneficios generales al hacer que el proveedor use SP que SQL ad-hoc.

Daniel Adeniji
fuente
Gracias, todos los ID son creados por SQL Server. Entiendo que la bandera 2371 solo hace que las actualizaciones de estadísticas sean más frecuentes. A juzgar por la tabla en brentozar.com/archive/2016/03/… , nuestro tamaño de tabla (14 millones de filas) y el número de inserciones diarias (28.000 filas), las estadísticas solo se actualizarían cada 4 días aproximadamente, así que El extracto de los nuevos datos no se conocerá la mayoría de las veces. Las consultas que miré no son preocupantes, es entender cómo SQL Server marca la columna principal que me gustaría saber. Gracias de nuevo.
Nik