SQL 2016 Asserzione di SQL Server: File: <pageref.cpp>, line = 951 Asserzione non riuscita


8

Attualmente sto aggiornando il nostro data warehouse da SQL 2012 a SQL 2016. Ho il mio vecchio e nuovo DW in esecuzione fianco a fianco in parallelo.

Il mio processo ETL (un framework sviluppato in SSIS da una terza parte) ha funzionato con successo per più di 2 anni nel 2012 ma non riesce nel 2016. Finora i database e il processo ETL sono identici.

Entrambi i server sono macchine virtuali in esecuzione su VMWare. Old Server è Win 2008 con 24Gb di RAM. SQL 2012 Std. Mem massima impostata su 16 GB. Il nuovo server è Win 2012 con 64 GB di RAM. SQL 2016 dev. Mem massima impostata su 50 GB. Il nuovo DW esegue v13.0.1601.5 RTM Developer Edition (64 bit).

Durante l'esecuzione del mio processo ETL, i passaggi di caricamento che utilizzano un'unione SQL in una dimensione o tabella dei fatti falliscono con il seguente errore.

Testo intero:

DESCRIPTION: Asserzione di SQL Server: File:, line = 951 Asserzione non riuscita = 'IS_OFF (BUF_MINLOGGED, m_buf-> bstat) || pageModifyType! = PageModifyType_Contents || GetPagePtr () -> IsTextPage () '. Questo errore potrebbe essere correlato alla temporizzazione. Se l'errore persiste dopo aver rieseguito l'istruzione, utilizzare DBCC CHECKDB per verificare l'integrità strutturale del database o riavviare il server per assicurarsi che le strutture di dati in memoria non siano danneggiate.

Come raccomandato ho eseguito DBCC e non sono stati trovati errori. Ho anche riavviato SQL. Ho quindi riavviato il processo ETL e ho riscontrato lo stesso errore.

Le mie ricerche per questo errore mostrano che era noto un errore in SQL 2008, 2012 e 2014 e corretto in hotfix e aggiornamenti cumulativi successivi. quindi sono un po 'sorpreso di vederlo riapparire nel 2016.

I collegamenti che ho trovato dicono che influiscono su SSIS quando si tenta di eseguire inserimenti se il database è nel modello di recupero con registrazione semplice o in blocco. (Sono in esecuzione nel modello di recupero semplice)

Una soluzione suggerita è quella di cambiare il modello di recupero Db in FULL. Ho provato questo e funziona, ma non è molto una soluzione per un data warehouse.

Qualcun altro ha riscontrato questo nel 2016?

Qualcuno può suggerire soluzioni alternative?

aggiornamenti:

26/7/2016: Ho applicato l' aggiornamento critico KB3164398 (v13.0.1708.0) e il problema persiste.

27/7/2016: Ho applicato l' aggiornamento cumulativo CU1 KB3164674 (v13.0.2149.0).

3/8/2016: Errore durante la notte sul nostro cubo più piccolo. CU1 non ha risolto il problema. Oggi ho segnalato il bug su MS Connect e ho anche registrato una chiamata di supporto con Microsoft.

08/12/2016: MS-Support ha risposto inizialmente, ma le risposte erano "Non abbiamo una soluzione per questo". Il ragazzo del supporto stava per discuterne con i suoi colleghi e tornare da me. 8 giorni dopo non ho più avuto sue notizie.

Anche se non ho una "soluzione", abbiamo trovato una soluzione adatta a noi. Vedi la mia risposta postata.

29/9/2016. Ho applicato CU2 la scorsa settimana. Giovedì abbiamo accidentalmente eseguito una versione precedente dell'unione che non è riuscita nuovamente con lo stesso errore. Quindi .. CU2 non l'ha riparato neanche.

23/1/2017 : Ho applicato SP1 CU1 2016 e credo che questo abbia risolto il problema. In particolare KB3205964

Risposte:


2

Guardando il KB hai un paio di opzioni / soluzioni alternative:

  1. Passa al modello di recupero COMPLETO. Dici che "questa non è un'opzione per un magazzino", ma in realtà si tratta solo di impostare i backup del registro delle transazioni su base regolare, ad esempio 15 minuti, e poi di eliminarli. SSIS / Piani di manutenzione hanno compiti di magazzino per fare questo . Perderai le transazioni registrate in blocco, ma non ho mai scoperto che queste hanno fatto una grande differenza in termini di autonomia, solo le dimensioni del registro. Puoi persino fare il backup del registro su null che non descriverò qui. Se non sei sicuro di cosa fare, chiedi al DBA locale. La conservazione del backup del registro delle transazioni e dello spazio su disco sono problemi più facili da risolvere rispetto a errori fatali. Quando alla fine questo problema viene risolto, puoi tornare indietro.
  2. Il KB menziona "più istruzioni BULK INSERT in una singola transazione distribuita". Non è chiaro dalla tua domanda come sono impostati i tuoi inserti di massa. Stai utilizzando SSIS per eseguire attività "Esegui SQL" che utilizzano ilMERGEcomando? Cosa significa "INSERTI BULK multipli" qui? C'è un modo per convertire il tuo approccio in singoli INSERTI BULK, uno alla volta, ad esempio? In SSIS è possibile impostare temporaneamente 'MaxConcurrentExecutables' su 1 per esempio, vedere se questo aiuta. Collegalo a una variabile di configurazione in modo da poterlo modificare in un secondo momento. Ovviamente rallenterà le cose, ma preferisci che il tuo ETL finisca piuttosto che fallire rapidamente. Fare le cose in parallelo è un buon modello e un vero punto di forza di SSIS, ma puoi andare veloce come il tuo componente più lento; supponiamo che tu abbia 10 dimensioni che richiedono un minuto e un fatto che richiede un'ora, il tuo ETL termina in un'ora in parallelo o 1 ora in 10 minuti in serie.
  3. MERGEè bello ma ha alcuni problemi. Potresti considerare di riconvertire in INSERT/ UPDATE. Inoltre dovresti usare HOLDLOCKcon MERGEsecondo qui . Usi quel suggerimento? Fa qualche differenza a questo problema se lo fai? Abbiamo avuto un problema in una build di SQL 2014 all'inizio in cui l'utilizzo MERGEcon DML ( OUTPUTclausola) componibile nel columnstore causava questo tipo di affermazione: li ho costretti a rimuovere gli indici columnstore dalle dimensioni, che avevano aggiunto senza dirmelo.
  4. Che tipo di gestione delle transazioni stai facendo? A volte con ETL la posizione è ripetibile semplicemente rieseguendo. A volte ne hai bisogno per fallire e ripristinare. Come lo hai implementato? Può essere modificato in modo che non si tratti di "singola transazione distribuita"?

In bocca al lupo.


Ciao @wBob, grazie per la tua risposta. Per rispondere alle tue domande. 1. Stiamo parlando dell'estrazione di tabelle da 20-30 GB in un unico passaggio. spostando oltre 100 GB di dati. Sono preoccupato per l'estrazione dei registri TX e anche dell'archiviazione. Forse potrei fare il backup del registro un passo nell'ETL dopo ogni estratto ?. 2. Sì SSIS chiama un'attività SQL per eseguire un'unione. Ogni passaggio viene eseguito in sequenza. Al momento la fusione è l'unica attività in esecuzione. 3. Il nostro strumento ETL è un framework fornito da un fornitore. Ecco come funziona. Non sono sicuro dei suggerimenti. controllerò. 4. Nessuna gestione TX. SQL dritto.
Sir Swears-tanto

Quindi, se le esecuzioni riuscite non continuano, prova un t-log da 100 GB con backup dei log dopo ogni spostamento della tabella, che dovrebbe ordinarlo. Ovviamente devi testare. Altre caratteristiche che dovremmo conoscere sul target? Columnstore, partizionamento, indicizzazione eccessiva?
wBob,

Al momento non ci sono funzionalità che non sono già presenti nel nostro DW esistente nel 2012 standard. I nuovi DW / Datamarts sono copie esatte di originali, senza colonne o partizioni. Indici minimi (ma efficaci). Attualmente ci stiamo concentrando su una mossa della piattaforma come per like. Alla fine, il nostro nuovo prodotto DW sarà Enterprise 2016. Ma non stiamo aggiungendo funzionalità di livello Enterprise fino a quando le basi non funzioneranno.
Sir Swears-tanto

Ciao @ wBob. Abbiamo implementato il tuo suggerimento rompendo l'inserto dall'unione. Ma dato il modo in cui ho posto la domanda, non sono sicuro di quale sia la risposta corretta. ma penso che tu mi abbia portato a una soluzione valida e praticabile.
Sir Swears-tanto



1

Credo che abbiamo trovato un'altra soluzione alternativa. Sto postando la mia risposta perché penso possa essere utile ed è abbastanza diversa dal suggerimento di wBob.

Abbiamo modificato la parte di inserimento dell'istruzione di unione in modo che venga inserita in una tabella temporanea anziché nella destinazione originale.

Una volta eseguita l'istruzione merge, inseriamo da #table nella destinazione.

Non è l'ideale, ma almeno l'unione gestisce ancora la complessità del 'upsert' contrassegnando le righe che sono state ritirate / scadute.

Abbiamo riscontrato che questo è un compromesso accettabile rispetto al riscrivere completamente l'unione come inserti e aggiornamenti separati.

CREATE TABLE #Activity(
[ETL_ActivitySurrogateKey] [int] IDENTITY(1,1) NOT NULL,
[Field1] [varchar](255) NULL,
)

-- Insert statements for procedure here
INSERT INTO #Activity ( [Field1],2,3,etc )

SELECT [Field1],2,3,etc
FROM 
(
    MERGE [DDS_OZ_CC].[dimActivity] AS target 
    USING (
      SELECT [Field1],2,3,etc
      FROM [STAGE_OZ_CC].[Transform_Activity]
      ) as source
    ON
    (
      target.RowIsCurrent = source.RowIsCurrent
         AND target.[Field1] = source.[Field1]
    )
    WHEN MATCHED 
        AND (        
        EXISTS (SELECT target.Level5Id EXCEPT SELECT source.Level5Id)
    )
    THEN
      UPDATE SET 
        ETL_ValidToDateTime = source.ETL_ValidFromDateTime 
       ,ETL_RowIsCurrent = 0 
       ,ETL_LastTouchedBy = source.ETL_LastTouchedBy 
       ,ETL_RowChangeReason = 'SCD2 Retired' 

    WHEN NOT MATCHED THEN 
    INSERT 
    (    
     [Field1],2,3,etc
    )
    VALUES (      
      source.[Field1],2,3,etc
    )
       WHEN NOT MATCHED BY SOURCE AND target.ETL_RowIsCurrent = 1
       THEN UPDATE SET
       ETL_RowIsCurrent = 0 
       ,ETL_RowChangeReason = 'Fact Removed' 
       ,ETL_LastTouchedBy = 'Unknown'

  OUTPUT
    $action      
      ,source.[Field1],2,3,etc    

  ) AS MergeOutput
  (
    action  
    ,[Field1],2,3,etc   
  ) 

  WHERE ACTION = 'UPDATE' AND ETL_RowIsCurrent = 1

    INSERT INTO [DDS_OZ_CC].[dimActivity]
    ( [Field1],2,3,etc  )
    SELECT [Field1],2,3,etc
    FROM #Activity

    END

Ok grazie Peter. Solo per interesse, hai provato il suggerimento HOLDLOCK?
wBob,

No non l'ho fatto. Dopo aver letto l'articolo di Aaron Bertrands a questo proposito, ho capito che si trattava in realtà di problemi di concorrenza con più utenti. Nel nostro caso il processo ETL è l'unica cosa in esecuzione.
Sir Swears-tanto

Penso che valga la pena provare solo a vedere se hai un comportamento diverso, inoltre è probabilmente la migliore pratica, solo per dire che non sei concorrente ora non significa che potresti non essere in futuro. Comunque, ben fatto per trovare una soluzione e per il prossimo problema
:)

Mi sarebbe piaciuto, ma purtroppo siamo sotto vincoli di tempo. Una volta trovata una soluzione praticabile, il capo ha fatto una chiamata per andare avanti.
Sir Swears-tanto
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.