2010-02-15 7 views
3

Je travaille actuellement sur un package SSIS qui extrait une table d'une base de données à une autre. Les tables des deux bases de données utilisent la même colonne que la clé primaire. Mon instruction select pour extraire les données est une simple instruction select. Lorsque j'ai couru le paquet je recevais une erreur qu'il y avait des valeurs de clé primaire en double. J'ai revu mon instruction select et vérifié que mon instruction select ne retournait pas les lignes dupliquées. Donc, pour tester cela, j'ai retiré la clé primaire de la table que j'insère les données dans et réexécuter le paquet SSIS. Après avoir couru j'ai regardé la table pour voir quelles lignes étaient dupliquées. Ce que j'ai trouvé, c'est que les lignes qui étaient éditées pendant que l'extrait était en cours de duplication, il y avait un enregistrement avant l'édition, et un enregistrement après l'édition. Je pourrais facilement le dire parce que la table a un dernier champ modifié qui est mis à jour chaque fois qu'un enregistrement est mis à jour.Requête SQL Server renvoyant plusieurs lignes

J'ai ajouté un indicateur NOLOCK à mon instruction select, et il a cessé de renvoyer des lignes en double.

Alors ma question est pourquoi? Je m'attendais à ce qu'une instruction select avec un indicateur de table NOLOCK ait plus de chances de renvoyer des lignes dupliquées car elle n'utilise pas de verrouillage et qu'une instruction select sans l'indicateur NOLOCK doit utiliser le verrouillage pour s'assurer qu'il ne renvoie pas de doublon lignes

Voici l'instruction select que j'utilise pour sélectionner les données. Je vérifiaient que les jointures ne sont pas à l'origine pour les lignes en double:

SELECT pe.enc_id, 
     pe.enc_nbr, 
     pe.billable_ind, 
     pe.clinical_ind AS clinical_ind, 
     pe.budget_ind, 
     pe.print_stmt_ind, 
     pe.send_coll_letter_ind, 
     pe.outsource_exempt_ind, 
     cb.First_name + ' ' + cb.last_name AS CreatedBy, 
     pe.create_timestamp AS create_timestamp, 
     mb.first_name + ' ' + mb.last_name AS ModifiedBy, 
     pe.modify_timestamp AS modify_timestamp 
FROM patient_encounter pe WITH(NOLOCK) 
     LEFT OUTER JOIN user_mstr cb WITH(NOLOCK) ON 
      pe.created_by = cb.user_id 
     LEFT OUTER JOIN user_mstr mb WITH(NOLOCK) ON 
      pe.modified_by = mb.user_id 

Répondre

0

L'indice AVEC NOLOCK indique juste le serveur de base de données d'ignorer les verrous, et il suffit de sélectionner les valeurs actuelles de la base de données - par conséquent, il suffit de sélectionner tous la valeur courante de la ligne au moment où elle touche cette ligne.

Notez que vous n'obtiendrez pas les mises à jour dans la nouvelle table des lignes mises à jour.

Sans voir votre SQL, je suppose que la façon dont il a été construit, il a attrapé la ligne en cours, a attendu un verrou pour effacer, puis sélectionné la nouvelle ligne.

Verrouiller la totalité de la table empêcherait les modifications/les doublons, mais vous risquez de bloquer tout le monde hors de la table pendant que vous effectuez votre sélection.

EDIT: Pour votre information ALTERNATIVES: utilisez les READPAST-lignes verrouillées par d'autres processus sont sautées et TABLOCK-Lock au niveau de la table qui sera bien sûr de bloquer d'autres processus et pourrait ne pas désirer. REMARQUE: UPDLOCK est converti en XLOCK pendant l'écriture de la transaction.

Il existe deux catégories pour les indicateurs: granularité et niveau d'isolement. La granularité inclut PAGLOCK, NOLOCK, ROWLOCK et TABLOCK. Les indicateurs de niveau d'isolement incluent HOLDLOCK, NOLOCK, READCOMMITTED, REPEATABLEREAD et SERIALIZABLE. Un maximum de un de chaque groupe peut être utilisé.

EDIT2: Simplicité: READCOMMITTED: lecture des données uniquement à partir des transactions qui ont été validées. Ceci est le comportement par défaut. EDIT3: Plus d'info: Le NOLOCK lira les lignes, mais vous risquez de lire des données "sales" qui changeront ou des données qui n'existeront pas si un ROLLBACK arrive à une transaction qui peut affecter la précision de l'ensemble sélectionné.

L'autre information importante est de découvrir quels types de verrous les transactions utilisent afin que vous puissiez planifier en conséquence.

+0

Merci pour l'information. J'ai ajouté l'instruction select que j'utilise à la poste. Pourquoi prend-il deux fois la ligne? Après l'avoir lu la première fois, pourquoi une modification de l'enregistrement le ferait-il relire? –

+0

Gardez à l'esprit que les "astuces" peuvent être remplacées par le serveur, même si vous n'utilisez pas NOLOCK, il peut utiliser cela en interne, donc les lignes en double. –

+0

Bon point, merci. Y at-il de toute façon à dire ce qui est utilisé en interne? –

1

L'indicateur NOLOCK provoque des anomallies de lecture, et une telle anomalie est une lecture en double. Un tel lit sont fréquents si une mise à jour modifie la position de la ligne dans l'index numérisé par la requête:

  • que vous avez 2 lignes de la table, avec une clé d'identification, les lignes avec des valeurs clés 1 et 2
  • une requête (T1) exécute la table UPDATE la touche SET = 3 la clé WHERE = 1;
  • la deuxième requête (T2) exécute SELECT ... FROM table WITH (NOLOCK);
  • T1 verrouille la ligne avec la valeur de clé 1
  • T2
  • ne tient pas compte de la serrure T1 a et lit la ligne avec la valeur de clé 1
  • T2 continue et lit la ligne avec la valeur de clé 2
  • mise à jour de T1 la rangée, et la ligne est déplacé dans l'int index qu'il nouvelle position pour la valeur clé 3
  • T2 continue de scanner et lit la ligne avec la valeur clé 3

Ainsi, le SELECT a lu une ligne deux fois, alors qu'il avait la clef valeur 1 et une fois alors qu'il avait une valeur de clé 3. Ceci est juste un exemple trivial de ce qui peut arriver. En réalité, des requêtes plus complexes peuvent exécuter des plans complexes et utiliser d'autres index, tous sujets à de telles anomalies.

En résumé: l'indication NOLOCK est mauvaise. Si vous voulez éviter les conflits, utilisez snapshot isolation.

+0

Merci pour la réponse, et la bonne explication de NOLOCK. Ce qui m'embrouille, ce n'est pas que cela se produise quand j'utilise NOLOCK, mais que cela se passe quand je n'utilise pas NOLOCK. La colonne de la clé primaire n'est pas modifiée, l'enregistrement a mis à jour les champs non id, et il est en cours de lecture deux fois lorsque je n'utilise pas NOLOCK. –

+0

Désolé de lire votre question en diagonale et en fait complètement manquer le point. –

+0

Pouvez-vous montrer un exemple d'édition qui se produit pendant l'extrait? –