Problema chiave crescente - Colonna principale con il marchio "Stazionario" - SQL Server


9

Ho cercato query a esecuzione lenta nel nostro database e ho concluso che si tratta di un classico problema chiave crescente. Poiché le nuove righe vengono inserite quasi costantemente e un dato pezzo di SQL per estrarre gli ultimi dati dal DB viene eseguito ogni 30 minuti, la prima opzione di aggiornamento delle statistiche ogni 30 minuti sembrava che potesse essere uno spreco di risorse.

Quindi, ho esaminato Trace Flag 2389 che in linea di principio dovrebbe aiutare, tuttavia ciò richiede che la colonna Leading sia contrassegnata come Ascendente e quando ho usato Trace Flag 2388 per controllare le statistiche dell'indice (PK), vedo che la colonna principale è in realtà bollato come Stazionario - come lo è per molti degli indici PK su altre tabelle aggiornati contemporaneamente.

inserisci qui la descrizione dell'immagine

Non sembra esserci molta guida su cosa si traduca in un marchio di Stationary, tuttavia ho trovato KB2952101 che dice che se meno del 90% degli inserti fosse maggiore del vecchio valore massimo, sarebbe classificato come Stazionario. Tutti i nostri inserti sono nuovi invii e la colonna principale è una colonna IDENTITÀ bigint, quindi il 100% degli inserti dovrebbe essere maggiore del valore massimo precedente.

Quindi la mia domanda è: perché la colonna dovrebbe essere etichettata come Fermo, quando è ovviamente crescente?

Un precedente tentativo di risolvere questo problema per alcuni SQL in esecuzione ogni giorno (che funzionava davvero bene) ha portato alla configurazione di un lavoro per aggiornare le statistiche per questa tabella ogni notte. L'aggiornamento non esegue un FULLSCAN, quindi potrebbe essere che a volte la scansione campionata manchi le nuove righe, quindi non viene sempre visualizzata come crescente?

L'unica altra cosa a cui riesco a pensare che potrebbe influire su questo, è che abbiamo un lavoro di archivio in esecuzione dietro le quinte che elimina le righe per una certa età. Questo potrebbe influire sul marchio?

Il server è SQL Server 2012 SP1.

Aggiornamento : un altro giorno, un altro aggiornamento delle statistiche - stesso marchio fisso. Ci sono stati 28049 nuovi inserti dal precedente aggiornamento delle statistiche. Ogni riga ha un timestamp di quando è stata inserita, quindi se seleziono max (id) dalla tabella in cui timestamp <'20161102' ottengo 23313455 Allo stesso modo, se lo faccio per quando le statistiche sono state aggiornate oggi, ottengo 23341504.

La differenza tra questi è i 28049 nuovi inserti, quindi, come puoi vedere, a tutti i nuovi inserti sono state assegnate nuove chiavi ascendenti (come previsto), suggerendo che la colonna principale dovrebbe essere marcata come crescente anziché stazionaria.

Nello stesso periodo, il nostro processo di archiviazione ha eliminato 213.629 righe (stiamo lentamente cancellando i vecchi dati). C'è qualche possibilità che un conteggio delle righe ridotto possa contribuire al marchio fisso? L'ho provato prima e non sembrava aver fatto alcuna differenza.

Aggiornamento 2 : un altro giorno, un altro aggiornamento delle statistiche e la colonna è ora contrassegnata come crescente! In base alla teoria sulle eliminazioni che influiscono su questo, ho verificato la percentuale di aggiornamenti che sono inserti rispetto alle eliminazioni e ieri il 13% erano inserti, mentre i due giorni precedenti rappresentavano circa il 12%. Non penso che ci dia qualcosa di conclusivo.

È interessante notare che una tabella correlata che ottiene in media 4 righe inserite per ogni riga inserita in questa tabella principale, e ha le sue statistiche aggiornate allo stesso tempo, ha la colonna IDENTITY PK ancora come Stazionaria !?

Aggiornamento 3 : nel fine settimana riceviamo più inserti. Questa mattina la colonna principale è tornata a Fermo. Nell'ultimo aggiornamento delle statistiche, abbiamo avuto 46840 inserti e solo 34776 eliminazioni.

Ancora una volta, è interessante notare che la tabella correlata che ho menzionato sopra ora ha la colonna principale con il marchio Ascendente. Non c'è documentazione che possa spiegare questo?

Aggiornamento 4 : è passata una settimana circa, il processo di archiviazione ha cancellato il backlog, quindi stiamo eliminando costantemente circa i due terzi del numero di righe da inserire. Le statistiche mostrano risultati contrastanti attraverso le relative tabelle, con una che mostra stazionaria e due che mostrano un ordine crescente, nonostante siano state tutte aggiornate in modo simile in modo simile.


Nel nostro caso, tutti gli inserti hanno valori che vanno oltre il valore più alto nell'istogramma, quindi la colonna non deve essere contrassegnata come Stazionaria, quindi non ho provato la bandiera. È una spiegazione del perché SQL Server sembra marcare casualmente le colonne che sto davvero cercando. Grazie.
Nik,

Risposte:


3

Non sembra esserci molta guida su cosa si traduca in un marchio di Stationary, tuttavia ho trovato KB2952101 che dice che se meno del 90% degli inserti fosse maggiore del vecchio valore massimo, sarebbe classificato come Stazionario. Tutti i nostri inserti sono nuovi invii e la colonna principale è una colonna IDENTITÀ bigint, quindi il 100% degli inserti dovrebbe essere maggiore del valore massimo precedente.

Quindi la mia domanda è: perché la colonna dovrebbe essere etichettata come Fermo, quando è ovviamente crescente?

Verrà marchiato come fermo se, come hai già affermato, il 10% o più degli inserti non stanno ascendendo. Se il 100% dei tuoi inserti fosse come dici tu ... allora potresti non avere questo problema, fino a quando ovviamente non lo elimini ma poi tornerebbe a sconosciuto.

Ecco una replica del tuo 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

Ho fatto un test rapido usando lo stesso script sopra ma ho eseguito solo l'inserimento e l'eliminazione di parti. Sembra che se si elimina una quantità enormemente maggiore di righe rispetto a quelle inserite, tornerà alla posizione fissa (di nuovo circa il 10%). Nei tuoi dati aggiornati, hai inserito circa il 10% di tutte le modifiche apportate ai dati: sembra che le eliminazioni ti facciano soffrire. A questo punto suggerirei di far salire l'oggetto stat in ordine crescente e poi congelarlo non aggiornandolo.
Sean Gallardy - Utente pensionato

Ho provato a ricreare quello che hai fatto, e ho finito per aggiungere altre 10 righe ed eliminare 1000, aggiornare le statistiche, quindi mostrare le statistiche e mostra ancora come crescente: Inserisce dall'ultimo aggiornamento: 10, Elimina dall'ultimo aggiornamento: 1000, Tipo di colonna principale : Crescente. Non sei sicuro del perché ottengo un risultato diverso per te? Se i risultati sono corretti, potrebbe essere solo un caso di tollerare risultati non ottimali ora, quindi quando il nostro arretrato di archiviazione è stato cancellato, riprovare.
Nik,

0

A mio avviso, a meno che non si stia generando la colonna chiave principale sul server stesso, è possibile entrare in piccole buche basandosi sul fatto che viene generato sui singoli client.

Inoltre, hai provato Trace Flag 2371.

TF 2371 è documentato qui .

Il KB si chiama "Controllo del comportamento di Autostat (AUTO_UPDATE_STATISTICS) in SQL Server." e il KB è 2754171.

Sarà molto utile se tu dovessi elencare per noi gli impatti effettivi dei nuovi dati senza farli entrare nelle statistiche in tempo.

Sono stati scelti indici errati. E, in tal caso, puoi elencarci gli indici e le loro chiavi primarie?

Inoltre, puoi condividere i piani che vengono generati quando le statistiche sono datate e quando sono tempestive. Mi piacerebbe confrontare i due.

Il mio pensiero è che le decisioni di SQL Cost Based Optimizer (Rules and Costing) siano abbastanza buone; al di fuori di aree esoteriche come questa.

Se si tratta di un caso speciale, ulteriori spiegazioni potrebbero essere utili e giustificare l'apertura di un articolo Connect.

A parte questo, a mio modesto parere, avrai maggiori vantaggi complessivi nel far utilizzare SP dal fornitore rispetto all'SQL ad hoc.


Grazie, gli ID sono tutti creati da SQL Server. Capisco che la bandiera 2371 rende solo gli aggiornamenti delle statistiche più frequenti. A giudicare dalla tabella su brentozar.com/archive/2016/03/… , dalle dimensioni della nostra tabella (14 milioni di righe) e dal numero di inserimenti giornalieri (28.000 righe), le statistiche verrebbero comunque aggiornate solo ogni 4 giorni circa, quindi l'estrazione di nuovi dati non avverrà il più delle volte. Le query che ho esaminato non sono preoccupanti, è capire come SQL Server contrassegna la colonna principale che mi piacerebbe sapere. Grazie ancora.
Nik,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.