web-dev-qa-db-fra.com

Comment tester une instruction SQL Update avant de l'exécuter?

Dans certains cas, l'exécution d'une instruction UPDATE en production peut faire gagner du temps. Cependant, une mise à jour compliquée peut être pire que le problème initial.

À part l’utilisation d’une base de données de test, quelles sont les options permettant de savoir ce qu’une instruction de mise à jour fera avant de l’exécuter?

69
static_rtti

En plus d'utiliser une transaction comme Imad l'a dit (ce qui devrait être obligatoire de toute façon), vous pouvez également vérifier l'intégrité des lignes affectées par l'exécution d'une sélection utilisant la même clause WHERE que UPDATE.

Donc, si vous mettez à jour est 

UPDATE foo
  SET bar = 42
WHERE col1 = 1
  AND col2 = 'foobar';

Ce qui suit vous montrera quelles lignes seront mises à jour:

SELECT *
FROM foo
WHERE col1 = 1
  AND col2 = 'foobar';
33

Autocommit OFF ...

MySQL

set autocommit=0;

Il désactive l'auto-validation pour la session en cours.

Vous exécutez votre déclaration, voyez ce qu'elle a changé, puis annulez si elle est fausse ou commettez si c'est ce que vous attendiez!

EDIT: L’avantage d’utiliser des transactions au lieu d’exécuter une requête select est que vous pouvez vérifier le jeu résultant plus facilement.

48
Imad Moqaddem

Qu'en est-il des transactions? Ils ont le ROLLBACK-Feature.

@see https://dev.mysql.com/doc/refman/5.0/fr/commit.html

Par exemple:

START TRANSACTION;
SELECT * FROM nicetable WHERE somthing=1;
UPDATE nicetable SET nicefield='VALUE' WHERE somthing=1;
SELECT * FROM nicetable WHERE somthing=1; #check

COMMIT;
# or if you want to reset changes 
ROLLBACK;

SELECT * FROM nicetable WHERE somthing=1; #should be the old value

Réponse à la question de @rickozoe ci-dessous:

En général, ces lignes ne seront pas exécutées comme une fois. Dans PHP f.e. vous écririez quelque chose comme ça (peut-être un peu plus propre, mais je voulais répondre rapidement ;-)):

$MysqlConnection->query('START TRANSACTION;');
$erg = $MysqlConnection->query('UPDATE MyGuests SET lastname='Doe' WHERE id=2;');
if($erg)
    $MysqlConnection->query('COMMIT;');
else
    $MysqlConnection->query('ROLLBACK;');

Une autre solution consiste à utiliser les variables MySQL (voir https://dev.mysql.com/doc/refman/5.7/fr/user-variables.htm l Et https://stackoverflow.com/a/18499823/1416909 ):

# do some stuff that should be conditionally rollbacked later on

SET @v1 := UPDATE MyGuests SET lastname='Doe' WHERE id=2;
IF(v1 < 1) THEN
    ROLLBACK;
ELSE
    COMMIT;
END IF;

Mais je suggérerais d'utiliser les enveloppes de langue disponibles dans votre langage de programmation préféré.

46
Marcel Lange

Je sais que ceci est une répétition d'autres réponses, mais il dispose d'un certain soutien émotionnel pour franchir l'étape supplémentaire de la mise à jour des tests: D

Pour tester la mise à jour, hash # est votre ami.

Si vous avez une déclaration de mise à jour comme:

UPDATE 
wp_history
SET history_by="admin"
WHERE
history_ip LIKE '123%'

Vous hachez UPDATE et SET pour les tester, puis vous les retournez:

SELECT * FROM
#UPDATE
wp_history
#SET history_by="admin"
WHERE
history_ip LIKE '123%'

Cela fonctionne pour des déclarations simples.

Une solution supplémentaire pratiquement obligatoire consiste à obtenir une copie (copie de sauvegarde) chaque fois que vous utilisez la mise à jour sur une table de production. Phpmyadmin> operations> copy: table_yearmonthday. Cela ne prend que quelques secondes pour les tables <= 100M.

9
Johan

Ce n’est pas une réponse directe, mais j’ai déjà vu beaucoup de situations de données délirantes qui auraient pu être évitées en en tapant d’abord la clause WHERE! Parfois, un WHERE 1 = 0 peut également aider à rédiger une déclaration de travail en toute sécurité. Et examiner un plan d'exécution estimé, qui permettra d'estimer les lignes affectées, peut être utile. Au-delà de cela, dans une transaction que vous annulez comme d'autres l'ont dit.

4
David M

Exécutez la requête select sur la même table avec toutes les conditions where que vous appliquez dans la requête de mise à jour.

1
manurajhada

en faire une SELECT,

comme si tu avais

UPDATE users SET id=0 WHERE name='jan'

le convertir en

SELECT * FROM users WHERE name='jan'

0
EaterOfCode

Dans les cas que vous souhaitez tester, il est judicieux de vous concentrer uniquement sur les valeurs de colonne current et les valeurs de colonne soon-to-be-be-updated.

Veuillez regarder le code suivant que j'ai écrit pour mettre à jour les prix WHMCS:

# UPDATE tblinvoiceitems AS ii

SELECT                        ###  JUST
    ii.amount AS old_value,   ###  FOR
    h.amount AS new_value     ###  TESTING
FROM tblinvoiceitems AS ii    ###  PURPOSES.

JOIN tblhosting AS h ON ii.relid = h.id
JOIN tblinvoices AS i ON ii.invoiceid = i.id

WHERE ii.amount <> h.amount   ### Show only updatable rows

# SET ii.amount = h.amount

De cette façon, nous comparons clairement les valeurs existantes aux nouvelles valeurs.

0
Mohammad Naji