Cet article décrit un problème qui se produit lors d’une requête d’un index columnstore cluster dans Microsoft SQL Server 2014. Cet article fournit une résolution à ce problème.
Résumé
Lorsque vous utilisez une requête qui analyse un index columnstore cluster dans Microsoft SQL Server 2014, vous pouvez, dans de rares conditions, recevoir des résultats de requête partiels.
Ce problème se produit lorsque l’opération suivante est exécutée.
Étape 1
Une instruction Transact-SQL [INSERT ou BULK-INSERT] insère des données dans une table qui a un index columnstore cluster. Au cours de cette opération, les conditions suivantes s’appliquent :
- Lorsque l’instruction Transact-SQL atteint le seuil rowgroup, elle ferme rowgroup R1 qui a le segment S1.
- Le segment S1 pointe vers le dictionnaire local D1.
- L’instruction continue d’insérer des lignes dans le nouveau rowgroup R2.
- Lorsque rowgroup R1 est fermé, le dictionnaire local D1 n’a pas non plus besoin d’être fermé. Si le dictionnaire D1 a encore de l’espace disponible, vous pouvez le laisser ouvert et le réutiliser pour le nouveau rowgroup R2.
Étape 2
Si l’instruction Transact-SQL est terminée anormalement ou annulée avant la fermeture du nouveau rowgroup R2, les conditions suivantes s’appliquent :
- Les modifications des métadonnées columnstore se produisent dans les sous-transactions qui sont validées indépendamment de la transaction externe.
- À ce stade, rowgroup R1 persiste dans la table système dans un état « en cours de construction » ou INVISIBLE, et segmente le dictionnaire de références S1 D1.
- Aucune ligne n’est créée dans la table système pour le dictionnaire D1. Cela est dû au fait que l’instruction Transact-SQL n’a jamais la possibilité de fermer la ligne existante. Par conséquent, la ligne existante persiste.
Étape 3
Dans une situation classique, si la tâche en arrière-plan du tuple mover démarre après la fin de l’instruction Transact-SQL, la tâche en arrière-plan supprime le rowgroup invisible R1 et le segment S1. Si une nouvelle instruction Transact-SQL est démarrée maintenant et crée rowgroup R3 avec un nouveau segment S3 qui nécessite un nouveau dictionnaire local, vous ne pouvez pas réutiliser l’ID interne du dictionnaire D1. Cela est dû au fait que l’état en mémoire du columnstore effectue le suivi des ID de dictionnaire utilisés. Par conséquent, le segment S3 fait référence au nouveau dictionnaire D2.
Remarque La condition de cette étape est une condition courante. Par conséquent, aucune altération ne se produit.
Étape 4
Si SQL Server perd l’état en mémoire du dictionnaire D1 avant que la tâche de déplacement de tuple n’entre en vigueur (et s’exécute comme décrit à l’étape 3), le problème décrit dans cet article se produit.
Notes
Cet événement se produit pour l’une des raisons suivantes :
- SQL Server subit une surcharge de mémoire, et le contenu en mémoire du dictionnaire D1 est supprimé de la mémoire.
- La instance de SQL Server est redémarrée.
- La base de données qui contient l’index columnstore cluster est mise hors connexion, puis revient en ligne.
Une fois que l’un de ces événements se produit et que SQL Server recharge les structures en mémoire, il n’existe aucun enregistrement indiquant qu’un dictionnaire D1 et son ID interne existaient. Cela est dû au fait que le dictionnaire D1 n’a pas été conservé dans les tables système lorsque l’instruction Transact-SQL a été arrêtée ou concelée.
Si la tâche en arrière-plan du tuple mover démarre à ce stade, aucune erreur ne se produit, car les conditions décrites à l’étape 3 s’appliquent.
Si un nouveau rowgroup R3 est créé avant le démarrage de la tâche en arrière-plan du tuple mover (conformément à l’élément à puces précédent), SQL Server attribue le même ID interne au nouveau dictionnaire D1 et fait référence au dictionnaire D1 pour le segment S3 dans rowgroup R3.
Lorsque la tâche en arrière-plan du mouvement de tuple démarre après l’action précédente, elle supprime le rowgroup invisible R1 et ses segments S1 avec le nouveau dictionnaire D1. Cela se produit parce que le tuple mover considère que le nouveau dictionnaire D1 et le dictionnaire D1 d’origine référencé par S1 sont identiques.
Remarque Lorsque cette condition se produit, vous ne pouvez pas interroger le contenu du rowgroup R3.
Résolution
Le problème a été résolu pour la première fois dans les mises à jour cumulatives suivantes pour SQL Server :
Mise à jour cumulative 1 pour SQL Server 2014 SP1
Mise à jour cumulative 8 pour SQL Server 2014
Le correctif de ce problème est également inclus dans les mises à jour de la version de distribution générale (GDR) suivantes :
Mise à jour de sécurité pour SQL Server 2014 QFE
Cette mise à jour inclut la mise à jour cumulative 8, ce correctif important et les mises à jour de sécurité MS15-058 requises.
Mise à jour de sécurité pour SQL Server 2014 GDR
Cette mise à jour inclut ce correctif important et des correctifs de sécurité cumulatifs via MS15-058.
Mise à jour sans sécurité pour SQL Server 2014 Service Pack 1 GDR
Cette mise à jour inclut uniquement ce correctif important.
À propos des mises à jour cumulatives pour SQL Server
Chaque nouvelle mise à jour cumulative pour SQL Server contient tous les correctifs logiciels et tous les correctifs de sécurité inclus dans la mise à jour cumulative précédente. Consultez les dernières mises à jour cumulatives pour SQL Server :
- Dernière mise à jour cumulative pour SQL Server 2014 SP1
- Dernière mise à jour cumulative pour SQL Server 2014
Informations supplémentaires
Messages d’erreurDans une base de données actuellement affectée, si vous exécutez DBCC CHECKDB après avoir appliqué ce correctif, vous recevez le message d’erreur suivant :
Remarque
Msg 5289, Niveau 16, État 1, Ligne 1
L’index columnstore cluster 'cci' sur la table 't' a une ou plusieurs valeurs de données qui ne correspondent pas aux valeurs de données d’un dictionnaire. Restaurez les données à partir d’une sauvegarde.
Dans une base de données actuellement affectée, lorsque vous exécutez une requête qui analyse les tables affectées après avoir appliqué ce correctif, vous recevez le message d’erreur suivant :
Remarque
Message 5288, niveau 16, état 1, ligne 1
L’index Columnstore contient une ou plusieurs valeurs de données qui ne correspondent pas aux valeurs de données d’un dictionnaire. Exécutez DBCC CHECKDB pour plus d’informations.
Si vous recevez ces erreurs, vous pouvez enregistrer les données non endommagées en exportant en bloc les données des colonnes/groupes de lignes non affectés, puis en rechargeant les données après avoir supprimé ou créé l’index columnstore cluster. Vous devez activer l’indicateur de trace 10207 pour supprimer l’erreur 5288 et revenir à l’ancien comportement d’ignorer les rowgroups endommagés.
Remarque Les messages d’erreur 5288 et 5289 sont générés pour ce rowgroup R3 qui a le segment S3. L’indicateur de trace 10207 est utilisé pour extraire les segments de rowgroup R3 qui ne sont pas affectés par le dictionnaire D1 manquant.
Requête pour les bases de données affectéesPour déterminer si la base de données qui contient des index columnstore est déjà affectée par ce problème, exécutez la requête suivante :
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
Notes
Vous devez exécuter cette requête sur chaque base de données qui contient des index columnstore sur le serveur qui exécute SQL Server. Un jeu de résultats vide indique que la base de données n’est pas affectée.
Exécutez cette requête pendant une période où aucune activité ne crée de rowgroups ou modifie l’état des rowgroups existants. Par exemple, les activités suivantes peuvent modifier l’état des rowgroups : build d’index, réorganisation d’index, insertion en bloc, tuple mover compressing delta stores.
Avant d’exécuter la requête, vous pouvez désactiver la tâche de déplacement de tuple en arrière-plan à l’aide de l’indicateur de trace 634. Utilisez cette commande pour désactiver la tâche en arrière-plan : DBCC TRACEON ( 634 , -1 ). Une fois l’exécution de la requête terminée, n’oubliez pas de réactiver la tâche en arrière-plan à l’aide de la commande DBCC TRACEOFF ( 634 , -1 ).
Vérifiez également qu’aucune commande BULK INSERT/BCP/SELECT-INTO n’insère des données dans les tables qui utilisent l’index columnstore pendant l’exécution de cette requête.
Il est recommandé d’utiliser ces étapes pour empêcher la requête de retourner des faux positifs.
État
Microsoft a confirmé qu’il s’agissait d’un problème dans les produits Microsoft répertoriés dans la section « S’applique à ».