KB3067257 - FIX: Risultati parziali in una query di un indice columnstore cluster in SQL Server 2014

Si applica a
SQL Server 2014 Developer - duplicate (do not use) SQL Server 2014 Enterprise - duplicate (do not use) SQL Server 2014 Standard - duplicate (do not use)

Questo articolo descrive un problema che si verifica durante una query di un indice columnstore cluster in Microsoft SQL Server 2014. Questo articolo fornisce una soluzione a questo problema.

Riepilogo

Quando si usa una query che analizza un indice columnstore cluster in Microsoft SQL Server 2014, in rari casi si possono ricevere risultati parziali della query.

Questo problema si verifica quando si esegue l'operazione seguente.

Passaggio 1

Un'istruzione Transact-SQL [INSERT o BULK-INSERT] inserisce i dati in una tabella con indice columnstore cluster. Durante questa operazione, si applicano le condizioni seguenti:

  • Quando l'istruzione Transact-SQL raggiunge la soglia del rowgroup, chiude il rowgroup R1 con il segmento S1.
  • Il segmento S1 punta al dizionario locale D1.
  • L'istruzione continua a inserire righe nel nuovo rowgroup R2.
  • Quando rowgroup R1 è chiuso, non è necessario chiudere anche il dizionario locale D1. Se il dizionario D1 ha ancora spazio disponibile, è possibile lasciarlo aperto e riutilizzarlo per il nuovo rowgroup R2.

Passaggio 2

Se l'istruzione Transact-SQL viene terminata in modo anomalo o annullata prima di chiudere il nuovo rowgroup R2, si applicano le condizioni seguenti:

  • Le modifiche ai metadati columnstore si verificano in transazioni secondarie che eseguono il commit indipendentemente dalla transazione esterna.
  • A questo punto, il rowgroup R1 persiste nella tabella di sistema in uno stato "in costruzione" o INVISIBILE e il segmento S1 fa riferimento al dizionario D1.
  • Non è stata creata alcuna riga nella tabella di sistema per il dizionario D1. Ciò è dovuto al fatto che l'istruzione Transact-SQL non ha mai l'opportunità di chiudere la riga esistente. Di conseguenza, la riga esistente viene mantenuta.

Passaggio 3

In una situazione tipica, se l'attività in background di spostamento tuple viene avviata dopo il termine dell'istruzione Transact-SQL, l'attività in background rimuove il rowgroup invisibile R1 e il segmento S1. Se una nuova istruzione Transact-SQL viene avviata ora e crea rowgroup R3 con un nuovo segmento S3 che richiede un nuovo dizionario locale, non è possibile riutilizzare l'ID interno del dizionario D1. Ciò è dovuto al fatto che lo stato in memoria del columnstore tiene traccia degli ID dizionario usati. Pertanto, il segmento S3 farà riferimento al nuovo dizionario D2.

Nota: la condizione in questo passaggio è una condizione comune. Pertanto, non si verifica alcun danneggiamento.

Passaggio 4

Se SQL Server perde lo stato in memoria del dizionario D1 prima che l'attività di spostamento della tupla abbia effetto (e venga eseguita come descritto nel passaggio 3), si verifica il problema descritto in questo articolo.

Note

  • Questo evento si verifica per uno dei motivi seguenti:

    • In SQL Server si verifica un sovraccarico di memoria e il contenuto in memoria del dizionario D1 viene rimosso dalla memoria.
    • L'istanza di SQL Server viene riavviata.
    • Il database che contiene l'indice columnstore cluster passa offline e quindi torna online.
  • Dopo che uno di questi eventi si verifica e SQL Server ricarica le strutture in memoria, non esiste alcuna registrazione dell'esistenza di un dizionario D1 e del relativo ID interno. Ciò è dovuto al fatto che il dizionario D1 non è stato mantenuto nelle tabelle di sistema quando l'istruzione Transact-SQL è stata terminata o nascosta.

  • Se l'attività in background di tuple mover viene avviata a questo punto, non si verificano errori perché si applicano le condizioni descritte nel passaggio 3.

  • Se un nuovo rowgroup R3 viene creato prima dell'avvio dell'attività in background di tuple mover (in base all'elemento dell'elenco puntato precedente), SQL Server assegna lo stesso ID interno al nuovo dizionario D1 e fa riferimento al dizionario D1 per il segmento S3 nel rowgroup R3.

  • Quando l'attività in background di spostamento delle tuple viene avviata dopo l'azione precedente, elimina il gruppo di righe invisibile R1 e i relativi segmenti S1 insieme al nuovo dizionario D1. Ciò si verifica perché il motore di tupla considera che il nuovo dizionario D1 e il dizionario originale D1 a cui S1 fa riferimento siano gli stessi.

    Nota: quando si verifica questa condizione, non è possibile eseguire query sul contenuto del rowgroup R3.

Risoluzione

Il problema è stato risolto per la prima volta negli aggiornamenti cumulativi seguenti per SQL Server:

Aggiornamento cumulativo 1 per SQL Server 2014 SP1
        
         Aggiornamento cumulativo 8 per SQL Server 2014
La correzione di questo problema è inclusa anche nei seguenti aggiornamenti GDR (General Distribution Release):

Aggiornamento della sicurezza per SQL Server 2014 QFE  
Questo aggiornamento include l'aggiornamento cumulativo 8, questa importante correzione e gli aggiornamenti della sicurezza MS15-058 richiesti.

Aggiornamento della sicurezza per SQL Server 2014 GDR  
Questo aggiornamento include questa importante correzione e le correzioni cumulative per la sicurezza attraverso il bollettino MS15-058.

Aggiornamento non relativo alla sicurezza per SQL Server 2014 Service Pack 1 GDR  
Questo aggiornamento include solo questa importante correzione.

Informazioni sugli aggiornamenti cumulativi per SQL Server

Ogni nuovo aggiornamento cumulativo per SQL Server contiene tutte le correzioni rapide e di sicurezza incluse nell'aggiornamento cumulativo precedente. Vedere gli aggiornamenti cumulativi più recenti per SQL Server:

      

Altre informazioni

Messaggi di erroreIn un database attualmente interessato, se si esegue DBCC CHECKDB dopo aver applicato questa correzione, viene visualizzato il seguente messaggio di errore:

Nota

Messaggio 5289, livello 16, stato 1, riga 1
L'indice columnstore cluster 'cci' nella tabella 't' contiene uno o più valori di dati che non corrispondono ai valori dei dati in un dizionario. Ripristinare i dati da un backup.

In un database attualmente interessato, quando si esegue una query che analizza le tabelle interessate dopo aver applicato questa correzione, viene visualizzato il messaggio di errore seguente:

Nota

Messaggio 5288, livello 16, stato 1, riga 1
L'indice columnstore include uno o più valori di dati che non corrispondono ai valori dei dati in un dizionario. Per altre informazioni, eseguire DBCC CHECKDB.

Se si ricevono questi errori, è possibile salvare i dati non danneggiati esportando in blocco i dati delle colonne/rowgroup non interessati e quindi ricaricando i dati dopo aver eliminato o creato l'indice columnstore cluster. È consigliabile abilitare il flag di traccia 10207 per eliminare l'errore 5288 e ripristinare il comportamento precedente di ignorare i rowgroup danneggiati.

Nota: i messaggi di errore 5288 e 5289 vengono generati per questo gruppo di righe R3 con il segmento S3. Il flag di traccia 10207 viene usato per estrarre i segmenti del rowgroup R3 non interessati dal dizionario D1 mancante.

Query per i database interessatiPer determinare se il database che contiene gli indici columnstore è già interessato da questo problema, eseguire la query seguente:

select  
       object_name(i.object_id) as table_name, 
       i.name as index_name, 
       p.partition_number, 
       count(distinct s.segment_id) as damaged_rowgroups 
from 
       sys.indexes i 
       join sys.partitions p on p.object_id = i.object_id and p.index_id = i.index_id 
       join sys.column_store_row_groups g on g.object_id = i.object_id and g.index_id = i.index_id and g.partition_number = p.partition_number 
       join sys.column_store_segments s on s.partition_id = p.partition_id and s.segment_id = g.row_group_id 
where  
       i.type in (5, 6) 
       and s.secondary_dictionary_id <> -1  
       and g.state_description = 'COMPRESSED' 
       and s.secondary_dictionary_id not in 
       ( 
              select dictionary_id from sys.column_store_dictionaries d 
              where d.hobt_id = p.hobt_id and d.column_id = s.column_id 
       ) 
group by  
       object_name(i.object_id), 
       i.name, 
       p.partition_number 

Note

  • È necessario eseguire questa query su ogni database che contiene indici columnstore nel server che esegue SQL Server. Un set di risultati vuoto indica che il database non è interessato.

  • Eseguire questa query durante un periodo in cui non è presente alcuna attività che creerà nuovi rowgroup o modificherà lo stato dei rowgroup esistenti. Ad esempio, le attività seguenti possono modificare lo stato dei rowgroup: compilazione indice, riorganizzazione indice, inserimento bulk, tuple mover compressione delta store.

    Prima di eseguire la query, è possibile disabilitare l'attività di spostamento della tupla in background usando il flag di traccia 634. Utilizzare questo comando per disabilitare l'attività in background: DBCC TRACEON ( 634 , -1 ). Al termine dell'esecuzione della query, ricordarsi di riabilitare l'attività in background usando il comando: DBCC TRACEOFF ( 634 , -1 ).

    Verificare inoltre che non siano presenti comandi BULK INSERT/BCP/SELECT-INTO che inseriscono dati nelle tabelle che usano l'indice columnstore durante l'esecuzione della query.

    È consigliabile usare questa procedura per evitare che la query restituisca falsi positivi.

Stato

Microsoft ha confermato che si tratta di un problema relativo ai prodotti elencati nella sezione "Si applica a".