2016-04-16 19 views
10

Abbiamo l'applicazione che scrive i registri nelle tabelle SQL di Azure. La struttura del tavolo è la seguente.Come ridurre l'utilizzo del log delle transazioni di SQL Server

CREATE TABLE [dbo].[xyz_event_history] 
(
    [event_history_id] [uniqueidentifier] NOT NULL, 
    [event_date_time] [datetime] NOT NULL, 
    [instance_id] [uniqueidentifier] NOT NULL, 
    [scheduled_task_id] [int] NOT NULL, 
    [scheduled_start_time] [datetime] NULL, 
    [actual_start_time] [datetime] NULL, 
    [actual_end_time] [datetime] NULL, 
    [status] [int] NOT NULL, 
    [log] [nvarchar](max) NULL, 

    CONSTRAINT [PK__crg_scheduler_event_history] PRIMARY KEY NONCLUSTERED 
    (
     [event_history_id] ASC 
    ) 
) 

tabella memorizzata come indice cluster da scheduled_task_id colonna (non unico).

CREATE CLUSTERED INDEX [IDX__xyz_event_history__scheduled_task_id] ON [dbo].[xyz_event_history] 
(
    [scheduled_task_id] ASC 
) 

Il event_history_id generato dall'applicazione, è casuale (non sequenziale) GUID. L'applicazione crea, aggiorna e rimuove le vecchie entità dalla tabella. La colonna log di solito contiene 2-10 KB di dati, ma in alcuni casi può raggiungere i 5-10 MB. Gli articoli sono generalmente accessibili da PK (event_history_id) e l'ordinamento più frequente è event_date_time desc.

Il problema che vediamo dopo aver abbassato il livello delle prestazioni per SQL SQL su "S3" (100 DTU) sta superando i limiti di velocità del registro delle transazioni. Può essere visto chiaramente nella tabella sys.dm_exec_requests - ci saranno record con tipo di attesa LOG_RATE_GOVERNOR (msdn).

Si verifica quando DB è in attesa della quota da scrivere nel registro.

Le operazioni che ho notato che causano grande impatto sul tasso di registro sono le eliminazioni da xyz_event_history e gli aggiornamenti in log colonna. Gli aggiornamenti fatti nel modo seguente.

UPDATE xyz_event_history 
SET [log] = COALESCE([log], '') + @log_to_append 
WHERE event_history_id = @id 

Il modello di recupero per i database SQL Azure è FULL e non può essere modificato.

Ecco le statistiche dell'indice fisico: ci sono molte pagine che hanno superato il limite di 8K per riga.

 
TableName   AllocUnitTp PgCt AvgPgSpcUsed  RcdCt MinRcdSz MaxRcdSz 
xyz_event_history IN_ROW_DATA 4145 47.6372868791698 43771 102   7864 
xyz_event_history IN_ROW_DATA 59  18.1995058067705 4145 11   19 
xyz_event_history IN_ROW_DATA 4  3.75277983691623 59  11   19 
xyz_event_history IN_ROW_DATA 1  0.914257474672597 4  11   19 
xyz_event_history LOB_DATA 168191 97.592290585619  169479 38   8068 
xyz_event_history IN_ROW_DATA 7062 3.65090190264393 43771 38   46 
xyz_event_history IN_ROW_DATA 99  22.0080800593032 7062 23   23 
xyz_event_history IN_ROW_DATA 1  30.5534964170991 99  23   23 
xyz_event_history IN_ROW_DATA 2339 9.15620212503089 43771 16   38 
xyz_event_history IN_ROW_DATA 96  8.70488015814184 2339 27   27 
xyz_event_history IN_ROW_DATA 1  34.3711391153941 96  27   27 
xyz_event_history IN_ROW_DATA 1054 26.5034840622683 43771 28   50 
xyz_event_history IN_ROW_DATA 139  3.81632073140598 1054 39   39 
xyz_event_history IN_ROW_DATA 1  70.3854707190511 139  39   39 
  • Esiste un modo per ridurre l'utilizzo di log delle transazioni?
  • In che modo il registro di SQL Server aggiorna le transazioni come nell'esempio sopra riportato? È solo un valore "vecchio" più "nuovo"? (Che sarebbe in teoria rendere l'aggiunta di piccoli pezzi di dati frequentemente del tutto inefficienti in termini di dimensioni del registro delle transazioni)

UPDATE (aprile, 20): Ho fatto alcuni esperimenti con suggerimenti in risposte e sono rimasto colpito dalla differenza rispetto a INSERT anziché a UPDATE.

di cui al successivo articolo di MSDN sulla struttura interna di registro delle transazioni di SQL Server (https://technet.microsoft.com/en-us/library/jj835093(v=sql.110).aspx):

i record di registrazione per registrare le modifiche dei dati o l'operazione logica eseguite o registrano la prima e dopo le immagini dei dati modificati . L'immagine precedente è una copia dei dati prima che l'operazione sia eseguita; l'immagine dopo è una copia dei dati dopo l'operazione è stata eseguita.

Questo rende automaticamente lo scenario con UPDATE ... SET X = X + 'more'altamente inefficiente in termini di utilizzo log delle transazioni - che richiede la cattura "prima immagine".

Ho creato semplice suite di test per testare modo originale di aggiungere dati a "log" colonna contro il modo in cui abbiamo appena inseriamo nuovo pezzo di dati nella nuova tabella. I risultati che ho ottenuto sono abbastanza sorprendenti (per quanto mi riguarda, non troppo esperto con il ragazzo di SQL Server).

Il test è semplice: 5'000 volte aggiungono pezzi lunghi 1'024 caratteri di registro - solo 5 MB di testo come il risultato (non troppo male come si potrebbe pensare).

FULL recovery mode, SQL Server 2014, Windows 10, SSD
 
        UPDATE   INSERT 
Duration    07:48 (!)  00:02 
Data file grow  ~8MB   ~8MB 
Tran. Log grow  ~218MB (!)  0MB (why?!) 

enter image description here

soli 5000 aggiornamenti che aggiungono 1 KB di dati può appendere fuori di SQL Server per 8 minuti (wow!) - non mi aspettavo che!

Penso domanda iniziale viene risolto a questo punto, ma i seguenti cresciuto:

  1. Perché log delle transazioni crescere sembra lineare (non quadratica, come ci si può aspettare quando semplicemente catturare "prima" e "dopo" immagini)? Dal diagramma possiamo vedere che gli "articoli al secondo" crescono proporzionalmente alla radice quadrata - è come previsto se il sovraccarico cresce in modo lineare con la quantità di articoli inseriti.
  2. Perché nel caso di inserimenti il ​​log delle transazioni sembra avere le stesse dimensioni di prima di qualsiasi inserimento? Ho preso uno sguardo sul log delle transazioni (con Dell's Toad) per il caso con inserti e si presenta come solo la scorsa 297 oggetti sono in là - plausibilmente log delle transazioni ricevuti troncati, ma perché se è FULL modalità di recupero?

AGGIORNAMENTO (21 aprile). DBCC LOGINFO uscita per custodia con INSERT - prima e dopo. La dimensione fisica del file di registro corrisponde all'output - esattamente 1.048.576 byte su disco. Perché sembra che il registro delle transazioni rimanga ancora?

 
RecoveryUnitId FileId FileSize StartOffset FSeqNo Status Parity CreateLSN 
0    2  253952  8192  131161 0  64  0   
0    2  253952  262144  131162 2  64  0   
0    2  253952  516096  131159 0  128  0   
0    2  278528  770048  131160 0  128  0   
 
RecoveryUnitId FileId FileSize StartOffset FSeqNo Status Parity CreateLSN 
0    2  253952  8192  131221 0  128  0   
0    2  253952  262144  131222 0  128  0   
0    2  253952  516096  131223 2  128  0   
0    2  278528  770048  131224 2  128  0   

Per coloro che interessati Ho registrato attività "sqlserv.exe" utilizzando Process Monitor - vedo che il file venga sovrascritto ancora e ancora - sembra tratta di SQL Server voci di registro vecchie come non più necessari per qualche motivo: https://dl.dropboxusercontent.com/u/1323651/stackoverflow-sql-server-transaction-log.pml.

UPDATE (aprile 24). Sembra che finalmente ho iniziato a capire cosa sta succedendo e voglio condividere con voi. Il ragionamento di cui sopra è vero in generale, ma ha un avvertimento serio che ha anche prodotto confusione sullo strano riutilizzo del registro delle transazioni con INSERT s.

Database si comporterà come in modalità di recupero SEMPLICE finché non venga presa primo backup completo (anche se è in modalità di recupero completo).

Siamo in grado di trattare i numeri e lo schema di cui sopra come vale per la modalità di recupero SIMPLE, e devo rifare la mia misura per realeFULL - sono ancora più sorprendente .

 
        UPDATE   INSERT 
Duration    13:20 (!)  00:02 
Data file grow   8MB   11MB 
Tran. log grow  55.2GB (!)  14MB 

real FULL recovery mode UPDATE stats

+0

è descritto tutto ciò che è consigliabile considerare http://dba.stackexchange.com/questions/29829/why-does-the-transaction-log-keep-growing-or-run-out-of-space –

+0

@PiotrLasota, grazie per il suggerimento, ma poiché usiamo Azure SQL non ci occupiamo della gestione dei backup dei log e cose del genere. Il modello di recupero completo viene anche applicato da SQL di Azure. –

+0

Evita gli aggiornamenti, il record tlog per un aggiornamento contiene i dati sia per annulla che per ripristina, ovvero i dati appena aggiornati e i dati prima dell'aggiornamento. Probabilmente inserirò solo gli inserti nella tua situazione. – dean

risposta

3

Si sta violando uno dei tenant di base del modulo normale con il campo del registro. Il campo di log si blocca per contenere una sequenza di informazioni che si aggiunge al primario. La soluzione è smettere di farlo.

1 Creare un tavolo. xyz_event_history_LOG (event_history_id, log_sequence #, log)

2 smettere di fare gli aggiornamenti al campo di registro in [xyz_event_history], invece fare inserti al xyz_event_history_LOG

La quantità di dati nel registro delle transazioni diminuirà notevolmente.

+0

È possibile fornire riferimenti a origini autorevoli o dettagli sugli interni del log delle transazioni di SQL Server? –

+0

@ EugeneD.Gubenkov puoi provarlo nel tuo ambiente locale? – cassandrad

+0

@cassandradied, quello che ho finalmente trovato il tempo di fare - si prega di vedere l'aggiornamento post! –

1

Il log delle transazioni contiene tutte le modifiche a un database nell'ordine in cui sono state fatte, quindi se si aggiorna una riga più volte si otterrà più voci a quella riga. Memorizza l'intero valore, vecchio e nuovo, quindi sei corretto che più aggiornamenti piccoli a un tipo di dati di grandi dimensioni come nvarchar (massimo) sarebbe inefficiente, sarebbe meglio archiviare gli aggiornamenti in colonne separate se sono solo piccoli valori.

+0

Esattamente! Apprezzo la tua risposta! –

Problemi correlati