113 votes

Le meilleur moyen de tester les requêtes SQL

Alors j'ai couru dans un problème que nous continuons à avoir des requêtes SQL complexes sortir avec des erreurs.

essentiellement, cela aboutit à l'envoi de courrier à la mauvaise clients et autres "problèmes" comme ça.

Qu'est-ce que tout le monde l'expérience de la création de requêtes SQL comme ça, pour l'essentiel, nous créons de nouvelles cohortes de données chaque semaine.

donc, ici, sont quelques-uns de mes pensées et les limites.

Création de données de test, alors que ce serait de prouver que nous avons toutes les données correctes, il ne fait pas valoir l'exclusion des anomalies dans la production. C'est des données qui seraient considérés comme mal aujourd'hui, mais peut-être raison il y a 10 ans, il n'était pas documentée et, par conséquent, nous ne connaissons à ce sujet après que les données sont extraites.

Créer des diagrammes de Venn et de cartes de données - ce qui semble être une bonne façon de tester la conception d'une requête, toutefois, il ne garantit pas que la mise en œuvre est correcte. il obtient les développeurs panoramique de l'avant et de penser à ce qui se passe lors de l'écriture.

Merci pour toute contribution que vous pouvez donner à mon problème.

174voto

tpdi Points 18427

Vous ne voudriez pas écrire une application avec des fonctions de 200 lignes de long. Vous auriez décomposer ces fonctions en plus petites fonctions, chacune avec un seul clairement définis responsabilité.

Pourquoi écrire de SQL comme ça?

Décomposer vos requêtes, tout comme vous le décomposer vos fonctions. Cela les rend plus court, plus simple, plus facile à comprendre, plus facile à tester, plus facile à refactoriser. Et il vous permet d'ajouter des "cales" entre eux, et des "wrappers" autour d'eux, comme vous le faites dans le code de procédure.

Comment faites-vous cela? En faisant de chaque chose importante, une requête n'est en vue. Ensuite à vous de composer des requêtes plus complexes de ces plus simples points de vue, tout comme vous composer des fonctions plus complexes des fonctions primitives.

Et la grande chose est, pour la plupart des compositions de vues, vous aurez exactement les mêmes performances de votre SGBDR. (Pour certains d'entre vous ne le ferez pas; et alors? L'optimisation prématurée est la racine de tous les maux. Code correctement d'abord, puis optimiser si vous en avez besoin.)

Voici un exemple d'utilisation de plusieurs vue de décomposer un complexe de requête.

Dans l'exemple, parce que chaque point de vue ajoute seulement une transformation, chacun peut être testé de façon indépendante à trouver des erreurs, et les tests sont simples.

Voici la table de base de l'exemple:

create table month_value( 
    eid int not null, m int, y int,  v int );

Ce tableau est imparfait, car il utilise deux colonnes, le mois et l'année, pour représenter une donnée, une absolue mois. Voici notre cahier des charges pour la nouvelle colonne calculée:

Nous allons le faire comme une transformation linéaire, tel qu'il trie la même chose que (y, m), et telle que pour tout (y,m) n-uplet il y a une et une seule valeur, et toutes les valeurs sont consécutifs:

create view cm_abs_month as 
select *, y * 12 + m as am from month_value;

Maintenant, ce que nous avons à tester est inhérente à notre spec, à savoir que pour tout n-uplet (y, m), il existe un et un seul (am), et que (am)s sont consécutifs. Nous allons écrire quelques tests.

Notre test sera un SQL select de la requête, avec la structure suivante: un nom de test et les cas de déclaration concated ensemble. Le nom de test est juste une chaîne de caractères arbitraire. L'instruction case est juste case when test consolidés then 'passed' else 'false' end.

Le test des déclarations sera juste SQL sélectionne (sous-requêtes) qui doit être vrai pour le test à passer.

Voici notre premier test:

--a select statement that catenates the test name and the case statement
select concat( 
-- the test name
'For every (y,m) there is one and only one (am): ', 
-- the case statement
   case when 
-- one or more subqueries
-- in this case, an expected value and an actual value 
-- that must be equal for the test to pass
  ( select count(distinct y, m) from month_value) 
  --expected value,
  = ( select count(distinct am) from cm_abs_month)  
  -- actual value
  -- the then and else branches of the case statement
  then 'passed' else 'failed' end
  -- close the concat function and terminate the query 
  ); 
  -- test result.

L'exécution de cette requête donne ce résultat: For every (y,m) there is one and only one (am): passed

Tant qu'il y a suffisamment de données de test dans month_value, ce test fonctionne.

Nous pouvons ajouter un test de suffisamment de données de test, trop:

select concat( 'Sufficient and sufficiently varied month_value test data: ',
   case when 
      ( select count(distinct y, m) from month_value) > 10
  and ( select count(distinct y) from month_value) > 3
  and ... more tests 
  then 'passed' else 'failed' end );

Maintenant, nous allons tester consécutives:

select concat( '(am)s are consecutive: ',
case when ( select count(*) from cm_abs_month a join cm_abs_month b 
on (( a.m + 1 = b.m and a.y = b.y) or (a.m = 12 and b.m = 1 and a.y + 1 = b.y) )  
where a.am + 1 <> b.am ) = 0 
then 'passed' else 'failed' end );

Maintenant, nous allons mettre nos tests, qui sont simplement des requêtes, dans un fichier, et lancez le script sur la base de données. En effet, si nous conservons notre vue de définitions dans un script (ou des scripts, je vous recommande un fichier par vues associées) à exécuter sur la base de données, nous pouvons ajouter nos tests pour chaque vue de la même script, de sorte que la loi de (re-) création de notre point de vue dirige également le point de vue de tests. De cette façon, nous avons tous deux obtenir des tests de régression lorsque nous re-créer des vues, et, lors de la création de la vue va à l'encontre de la production, de la vue seront également testés en production.

8voto

ojblass Points 7423

Créer un système de test de la base de données que vous pouvez recharger aussi souvent que vous le souhaitez. Charger vos données ou créer vos données et de les enregistrer. Produire un moyen facile de le recharger. Connectez votre système de développement à la base de données et de valider votre code avant de passer à la production. Coup de pied-vous à chaque fois que vous parvenez à laisser un problème entrer dans la production. Créer une suite de tests pour vérifier les problèmes connus et la croissance de votre suite de tests au cours du temps.

4voto

Jon Limjap Points 46429

Vous pourriez vouloir vérifier DbUnit, de sorte que vous pouvez essayer d'écrire des tests unitaires pour vos programmes avec un ensemble fixe de données. De cette façon, vous devriez être en mesure d'écrire des requêtes avec plus ou moins de résultats prévisibles.

L'autre chose que vous pouvez faire est le profil de votre SQL Server pile d'exécution et de savoir si toutes les requêtes sont en effet celles qui sont correctes, par exemple, si vous utilisez une requête qui renvoie à la fois correctes et incorrectes résultats, il est clair que la requête utilisé est en question, mais que diriez-vous si votre application est l'envoi de requêtes différentes à différents points dans le code?

Toute tentative pour résoudre votre requête, alors qu'il serait futile... le voleur de requêtes peuvent encore être ceux de tir les mauvais résultats de toute façon.

2voto

Re: tpdi

case when ( select count(*) from cm_abs_month a join cm_abs_month b  
on (( a.m + 1 = b.m and a.y = b.y) or (a.m = 12 and b.m = 1 and a.y + 1 = b.y) )   
where a.am + 1 <> b.am ) = 0  

Noter que cette fonction ne vérifie que suis des valeurs pour le mois consécutifs sont consécutifs, pas que de données consécutifs existe (ce qui est probablement ce que vous avez prévu initialement). Ce sera toujours passer si aucun de votre source de données consécutives (par exemple, vous n'avez même numérotée mois), même si votre calcul est totalement hors.

Aussi ai-je raté quelque chose, ou ne la seconde moitié de cette clause à la bosse de la mauvaise valeur de mois? (c'est à dire vérifie que 12/2011 vient après 1/2010)

Ce qui est pire, si je me souviens bien, SQL Server permet au moins vous avez moins de 10 niveaux de points de vue avant de l'optimiseur jette son virtuel mains en l'air et commence à faire des analyses de tables complètes sur chaque demande, afin de ne pas trop faire de cette approche.

N'oubliez pas de tester le diable hors de vos cas de test!

Sinon, la création d'un très large ensemble de données pour englober la plupart ou toutes les formes possibles d'entrées, à l'aide de SqlUnit ou DbUnit ou de tout autre *Unité d'automatiser la vérification de résultats attendus à l'encontre de ces données, et d' examiner, le maintien et la mise à jour en tant que de besoin en général semble être la voie à suivre.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X