Si j'ai une UPDATE
déclaration qui ne modifie en fait aucune donnée (car les données sont déjà à l'état mis à jour). Y a-t-il un avantage en termes de performances à cocher la WHERE
clause pour empêcher la mise à jour?
Par exemple, y aurait-il une différence de vitesse d'exécution entre UPDATE 1 et UPDATE 2 dans les cas suivants:
CREATE TABLE MyTable (ID int PRIMARY KEY, Value int);
INSERT INTO MyTable (ID, Value)
VALUES
(1, 1),
(2, 2),
(3, 3);
-- UPDATE 1
UPDATE MyTable
SET
Value = 2
WHERE
ID = 2
AND Value <> 2;
SELECT @@ROWCOUNT;
-- UPDATE 2
UPDATE MyTable
SET
Value = 2
WHERE
ID = 2;
SELECT @@ROWCOUNT;
DROP TABLE MyTable;
La raison pour laquelle je demande, c'est que j'ai besoin du nombre de lignes pour inclure la ligne inchangée, donc je sais si je dois faire une insertion si l'ID n'existe pas. En tant que tel, j'ai utilisé le formulaire UPDATE 2. S'il y a un avantage en termes de performances à utiliser le formulaire UPDATE 1, est-il possible d'obtenir le nombre de lignes dont j'ai besoin?
sql-server
query-performance
update
Martin Brown
la source
la source
Réponses:
Il pourrait certainement y en avoir car il y a une légère différence de performances due à la MISE À JOUR 1 :
Cependant, vous devez mesurer la différence qu'il y a sur votre système avec votre schéma, vos données et votre charge système. Plusieurs facteurs jouent sur l'impact d'une MISE À JOUR sans mise à jour:
UPDATE TableName SET Field1 = Field1
, un déclencheur de mise à jour se déclenchera et indiquera que le champ a été mis à jour (si vous vérifiez à l'aide des fonctions UPDATE () ou COLUMNS_UPDATED ), et que le champ dans les deuxINSERTED
et lesDELETED
tables ont la même valeur.En outre, la section récapitulative suivante se trouve dans l'article de Paul White, L'impact des mises à jour sans mise à jour (comme l'a noté @spaghettidba dans un commentaire sur sa réponse):
Veuillez garder à l'esprit (surtout si vous ne suivez pas le lien pour voir l'article complet de Paul), les deux éléments suivants:
Les mises à jour non mises à jour ont toujours une certaine activité de journal, indiquant qu'une transaction commence et se termine. C'est juste qu'aucune modification des données ne se produit (ce qui est toujours une bonne économie).
Comme je l'ai indiqué ci-dessus, vous devez tester sur votre système. Utilisez les mêmes requêtes de recherche que Paul utilise et voyez si vous obtenez les mêmes résultats. Je vois des résultats légèrement différents sur mon système que ce qui est indiqué dans l'article. Toujours pas de pages sales à écrire, mais un peu plus d'activité de journal.
Simplement, si vous ne traitez qu'avec une seule ligne, vous pouvez effectuer les opérations suivantes:
Pour plusieurs lignes, vous pouvez obtenir les informations nécessaires pour prendre cette décision en utilisant la
OUTPUT
clause. En capturant exactement quelles lignes ont été mises à jour, vous pouvez affiner les éléments à rechercher pour connaître la différence entre la non-mise à jour des lignes qui n'existent pas et la non-mise à jour des lignes qui existent mais n'ont pas besoin de la mise à jour.Je montre l'implémentation de base dans la réponse suivante:
Comment éviter d'utiliser la requête de fusion lors de la migration de plusieurs données à l'aide du paramètre xml?
La méthode indiquée dans cette réponse ne filtre pas les lignes qui existent mais n'ont pas besoin d'être mises à jour. Cette partie pourrait être ajoutée, mais vous devez d'abord montrer exactement où vous obtenez votre ensemble de données dans lequel vous fusionnez
MyTable
. Viennent-ils d'une table temporaire? Un paramètre table (TVP)?MISE À JOUR 1:
J'ai finalement pu faire quelques tests et voici ce que j'ai trouvé concernant le journal des transactions et le verrouillage. Tout d'abord, le schéma de la table:
Ensuite, le test met à jour le champ à la valeur qu'il a déjà:
Résultats:
Enfin, le test qui filtre la mise à jour car la valeur ne change pas:
Résultats:
Comme vous pouvez le voir, rien n'est écrit dans le journal des transactions lors du filtrage de la ligne, contrairement aux deux entrées marquant le début et la fin de la transaction. Et s'il est vrai que ces deux entrées ne sont presque rien, elles sont toujours quelque chose.
De plus, le verrouillage des ressources PAGE et KEY est moins restrictif lors du filtrage des lignes qui n'ont pas changé. Si aucun autre processus n'interagit avec cette table, il s'agit probablement d'un problème (mais quelle est la probabilité, vraiment?). Gardez à l'esprit que ce test affiché dans l'un des blogs liés (et même mes tests) suppose implicitement qu'il n'y a pas de conflit sur la table car il ne fait jamais partie des tests. Dire que les mises à jour non mises à jour sont si légères qu'elles ne paient pas pour faire le filtrage doit être pris avec un grain de sel puisque le test a été fait, plus ou moins, dans le vide. Mais en production, ce tableau n'est probablement pas isolé. Bien sûr, il se pourrait très bien que le peu de journalisation et les verrous plus restrictifs ne se traduisent pas par une efficacité moindre. Alors, la source d'information la plus fiable pour répondre à cette question? Serveur SQL. Plus précisément:votre serveur SQL. Il vous montrera quelle méthode est la meilleure pour votre système :-).
MISE À JOUR 2:
Si les opérations dans lesquelles la nouvelle valeur est identique à la valeur actuelle (c.-à-d. Pas de mise à jour) sortent le nombre d'opérations dans lesquelles la nouvelle valeur est différente et la mise à jour est nécessaire, alors le modèle suivant pourrait s'avérer encore meilleur, surtout si il y a beaucoup de conflits sur la table. L'idée est de faire un
SELECT
premier simple pour obtenir la valeur actuelle. Si vous n'obtenez pas de valeur, vous avez votre réponse concernant leINSERT
. Si vous avez une valeur, vous pouvez faire un simpleIF
et émettre leUPDATE
seul si c'est nécessaire.Résultats:
Il n'y a donc que 2 verrous acquis au lieu de 3, et ces deux verrous sont partagés intentionnellement, pas Intention eXclusive ou mise à jour d'intention ( compatibilité de verrouillage ). En gardant à l'esprit que chaque verrou acquis sera également libéré, chaque verrou est en réalité 2 opérations, donc cette nouvelle méthode est un total de 4 opérations au lieu des 6 opérations de la méthode initialement proposée. Considérant que cette opération s'exécute une fois toutes les 15 ms (environ, comme indiqué par l'OP), soit environ 66 fois par seconde. Ainsi, la proposition initiale équivaut à 396 opérations de verrouillage / déverrouillage par seconde, alors que cette nouvelle méthode ne représente que 264 opérations de verrouillage / déverrouillage par seconde de verrous encore plus légers. Ce n'est pas une garantie de performances impressionnantes, mais cela vaut certainement la peine d'être testé :-).
la source
Zoomez un peu et pensez à l'image plus grande. Dans le monde réel, votre déclaration de mise à jour ressemblera-t-elle vraiment à ceci:
Ou est-ce que ça va ressembler davantage à ceci:
Parce que dans le monde réel, les tableaux ont beaucoup de colonnes. Cela signifie que vous devrez générer beaucoup de logique d'application dynamique complexe pour créer des chaînes dynamiques, OU vous devrez spécifier à chaque fois le contenu avant et après de chaque champ.
Si vous créez ces instructions de mise à jour de manière dynamique pour chaque table, en ne transmettant que les champs en cours de mise à jour, vous pouvez rapidement rencontrer un problème de pollution de cache de plan similaire au problème de taille des paramètres NHibernate il y a quelques années. Pire encore, si vous générez les instructions de mise à jour dans SQL Server (comme dans les procédures stockées), vous brûlerez de précieux cycles CPU car SQL Server n'est pas très efficace pour concaténer des chaînes ensemble à grande échelle.
En raison de ces complexités, il n'est généralement pas judicieux de faire ce type de comparaison ligne par ligne, champ par champ pendant que vous effectuez les mises à jour. Pensez plutôt aux opérations basées sur des ensembles.
la source
Vous pouvez constater un gain de performances en sautant des lignes qui n'ont pas besoin d'être mises à jour uniquement lorsque le nombre de lignes est important (moins de journalisation, moins de pages sales à écrire sur le disque).
Lorsque vous traitez des mises à jour sur une seule ligne comme dans votre cas, la différence de performances est complètement négligeable. Si, dans tous les cas, la mise à jour des lignes vous facilite la tâche, faites-le.
Pour plus d'informations sur le sujet, voir Mises à jour sans mise à jour par Paul White
la source
Vous pouvez combiner la mise à jour et l'insérer dans une seule instruction. Sur SQL Server, vous pouvez utiliser une instruction MERGE pour effectuer à la fois la mise à jour et l'insérer si elle n'est pas trouvée. Pour MySQL, vous pouvez utiliser INSERT ON DUPLICATE KEY UPDATE .
la source
Au lieu de vérifier les valeurs de tous les champs, ne pouvez-vous pas obtenir une valeur de hachage en utilisant les colonnes qui vous intéressent, puis comparer cela au hachage stocké par rapport à la ligne du tableau?
la source