Database
 sql >> Base de données >  >> RDS >> Database

Si vous utilisez des vues indexées et MERGE, veuillez lire ceci !

Son collègue MVP Jamie Thomson a récemment souligné qu'il existe un bogue de "résultats erronés" dans SQL Server qui peut se manifester lorsque les conditions suivantes sont remplies :

  • Vous avez une vue indexée qui joint au moins deux tables ;
  • ces tables sont contraintes dans les deux sens par une clé étrangère à une seule colonne ;
  • vous effectuez des mises à jour de la ou des tables de base à l'aide de MERGE qui inclut à la fois UPDATE et (DELETE ou INSERT ) Actions; et,
  • vous émettez par la suite des requêtes qui référencent l'index sur la vue (intentionnellement ou non).

Malheureusement, l'article de la base de connaissances décrivant le problème (KB #2756471) est assez léger sur les détails. Ils ne vous disent pas comment reproduire le problème, ni même ce que vous devriez rechercher spécifiquement pour voir si cela vous affecte; et ils ne mentionnent même pas MERGE (qui est en fait le cœur du problème, pas NOEXPAND , et non une simple mise à jour). Il y a quelques détails supplémentaires dans l'élément Connect qui ont provoqué le correctif; j'espère que l'article de la base de connaissances sera mis à jour avec plus de détails d'ici peu.

En attendant, le résultat que vous pouvez voir est des données incorrectes - ou mieux, des données obsolètes  :La requête peut vous montrer l'ancienne version de la ou des lignes mises à jour ! J'ai passé quelques minutes à essayer de reproduire ce scénario dans AdventureWorks, et j'ai lamentablement échoué. Heureusement, Paul White (blog | @SQL_Kiwi) a écrit un article exceptionnel décrivant le scénario et montrant une reproduction complète du problème.

Je ne pense pas pouvoir souligner à quel point c'est sérieux.

Des millions de clients utilisent sûrement des vues indexées, beaucoup d'entre eux ont migré leur code DML pour utiliser MERGE , et un grand nombre d'entre eux sont sur Enterprise Edition (ou ne le sont pas mais utilisent le NOEXPAND indice ou font directement référence à l'index). Paul n'a pas tardé à souligner que NOEXPAND n'est pas obligé de reproduire le problème dans Enterprise Edition, et a également découvert de nombreux autres détails nécessaires pour reproduire le bogue.

Ce message n'est pas destiné à voler le tonnerre des messages de Jamie ou de Paul ; juste une tentative de réitérer la préoccupation et de sensibiliser à cette question. Si vous avez l'habitude d'ignorer les mises à jour cumulatives, en choisissant d'attendre les Service Packs, et qu'il y a une chance que ce problème vous affecte en ce moment, vous vous devez, sans parler de vos parties prenantes et de vos clients, de prendre ce problème au sérieux.

Alors, que devez-vous faire ?

Eh bien, ce que vous faites ensuite dépend de la version et de l'édition de SQL Server que vous utilisez, et si le bogue vous affecte (ou pourrait) réellement vous affecter.

    SQL Server 2008 SP3
    SQL Server 2008 R2 SP1/SP2
    SQL Server 2012 RTM/SP1

    Vos options si vous êtes sur l'une de ces versions :

    1. Vous devez mettre à jour la dernière mise à jour cumulative pour votre succursale :
      Branche Fixé en CU Construire Compilation minimale requise
      pour appliquer la mise à jour

      Article KB
      (Télécharger)
      2008 Service Pack 3 CU #8 10.00.5828 10.00.5500 KB #2771833
      2008 R2 Service Pack 1 CU #10 10.50.2868 10.50.2500 KB #2783135
      2008 R2 Service Pack 2 CU #4 10.50.4270 10.00.4000 KB #2777358
      RTM 2012 CU #5 11.00.2395 11.00.2100 KB #2777772
      2012 Service Pack 1 CU #2 11.00.3339 11.00.3000 KB #2790947

      Tableau 1 :Builds contenant le correctif

    2. Si vous n'appliquez pas le correctif, vous devez tester toutes les références à vos vues pour vérifier qu'elles renvoient des résultats corrects dans tous les cas, y compris après avoir mis à jour les tables de base à l'aide de MERGE . Si ce n'est pas le cas (ou si vous pensez qu'ils pourraient être affectés ultérieurement), vous devez reconstruire l'index clusterisé sur toutes les vues affectées (ou réparer la ou les vues indexées à l'aide de DBCC CHECKTABLE , comme Paul l'a décrit dans son message), et arrêtez d'utiliser MERGE contre ces tables jusqu'à ce que vous ayez appliqué le correctif. Si vous continuez à utiliser MERGE contre les tables de base, préparez-vous à continuer à réparer les vues afin d'éviter le problème.
    3. Une solution plus rapide consisterait à empêcher l'utilisation de la vue indexée endommagée, en utilisant l'une des méthodes suivantes :
      • appliquer l'indicateur de requête OPTION (EXPAND VIEWS) à toutes les requêtes pertinentes ;
      • supprimer toute référence explicite à l'index sur la vue ;
      • dans les éditions Standard ou autres où les vues indexées ne correspondent pas automatiquement, supprimez toutes les instances de NOEXPAND .

      Mais cela, bien sûr, irait à l'encontre de l'objectif de la vue indexée - autant supprimer l'index. Cela dit, il est généralement préférable d'obtenir les bons résultats lentement plutôt que d'obtenir rapidement les mauvais résultats. donc peut-être que ça va.

    SQL Server 2008 RTM/SP1/SP2
    SQL Server 2008 R2 RTM

    Malheureusement, vous êtes sur une version qui n'est plus prise en charge par le grand public et il est peu probable que ce problème soit résolu pour vous (sauf si vous bénéficiez d'une prise en charge étendue et que vous faites beaucoup de bruit). Vos options sont donc limitées ici - soit vous déplacez vers une branche prise en charge selon le tableau ci-dessus, et appliquez la mise à jour cumulative, soit choisissez l'une des autres options mentionnées précédemment.

    SQL Server 2000
    SQL Server 2005

    Eh bien, la mauvaise nouvelle est que vous êtes également sur une version qui n'est plus prise en charge. La bonne nouvelle est que dans ce cas précis, cela n'a pas d'importance - vous ne pouvez pas utiliser MERGE de toute façon, donc ce bogue ne peut pas vous affecter.

Autres problèmes de MERGE

Malheureusement, c'est loin d'être le premier bogue que nous avons vu avec MERGE , et ce ne sera probablement pas le dernier. Voici une sélection rapide d'une douzaine MERGE bugs toujours marqués comme actifs sur Connect :

  • #773895 :MERGE signale à tort des violations de clé unique
  • #766165 : MERGE évalue l'index filtré par ligne, et non après l'opération, ce qui entraîne une violation de l'index filtré
  • #723696 :upsert MERGE de base provoquant des interblocages
  • #713699 :Une vérification d'assertion système a échoué ("cxrowset.cpp":1528)
  • #699055 :les plans de requête MERGE autorisent les violations des contraintes FK et CHECK
  • #685800 :DELETE et MERGE paramétrés autorisent les violations de contrainte de clé étrangère
  • #654746 :la fusion dans SQL2008 SP2 souffre toujours de "Tentative de définition de la valeur d'une colonne non-NULL-able sur NULL"
  • #635778 :les parties NOT MATCHED et MATCHED d'une instruction SQL MERGE ne sont pas optimisées
  • #633132 :FUSIONNER AVEC UNE SOURCE FILTRÉE ne fonctionne pas correctement
  • #596086 :bogue de l'instruction MERGE lorsque INSERT/DELETE utilisait et filtrait l'index
  • #583719 :L'instruction MERGE traite les colonnes calculées non nullables de manière incorrecte dans certains scénarios
  • #539084 :MERGE Stmt :la condition de recherche sur une colonne non clé et un ORDER BY dans la table dérivée de la source rompent complètement la fusion

Maintenant, il se peut que certains de ces bogues aient été corrigés, mais leur statut est erroné car la boucle de retour à Connect n'a pas été fermée. Même si c'est le cas, cela ne peut pas être vrai pour tous (et potentiellement pour d'autres que je n'ai pas découverts).

De plus, il a été démontré par Dan Guzman que MERGE n'est pas à l'abri des conditions de concurrence et d'autres problèmes de concurrence. La solution consiste à utiliser HOLDLOCK (ou un niveau d'isolement supérieur); cependant, c'est une idée fausse commune que MERGE est complètement atomique et n'est pas du tout sujet à ce problème. Par conséquent, je vais me demander à haute voix :combien de MERGE les déclarations incluent HOLDLOCK (ou sont exécutés sous SERIALIZABLE ) ? Combien d'entre eux ont été minutieusement testés pour les problèmes liés à la simultanéité ?

Conclusion

Personnellement, je pense que la syntaxe est excellente (bien que décourageante à apprendre), mais chaque fois qu'un problème survient, cela érode ma confiance dans l'aspect pratique du remplacement du DML existant par la nouvelle construction.

Dans cet esprit, ne pas être Chicken Little, mais je ne me sentirais pas à l'aise de recommander à quiconque d'utiliser MERGE à moins qu'ils ne mettent en œuvre des tests extrêmement complets. Certains de ces problèmes sont également présents avec la norme UPSERT méthodologies, mais les problèmes y sont plus évidents. MERGE , simplement par sa nature à énoncé unique, vous donne envie de croire en la magie. Peut-être qu'un jour il tiendra ses promesses, mais pour l'instant je sais qu'il ne pourra pas scier une personne en deux sans une aide sérieuse.