Tous ceux qui travaillent avec des bases de données relationnelles ont appris (ou apprennent) que SQL est différent. Obtenir les résultats souhaités, et le faire efficacement, implique un processus fastidieux en partie caractérisé par l'apprentissage de paradigmes inconnus et la découverte que certains de nos modèles de programmation les plus familiers ne fonctionnent pas ici. Quels sont les antipatterns courants que vous avez vus (ou que vous avez commis)?
sql
anti-patterns
le dorfier
la source
la source
Réponses:
Je suis constamment déçu par la tendance de la plupart des programmeurs à mélanger leur logique d'interface utilisateur dans la couche d'accès aux données:
Normalement, les programmeurs le font car ils ont l'intention de lier leur ensemble de données directement à une grille, et c'est tout simplement pratique d'avoir le format SQL Server côté serveur que le format sur le client.
Les requêtes comme celle illustrée ci-dessus sont extrêmement fragiles car elles couplent étroitement la couche de données à la couche d'interface utilisateur. En plus de cela, ce style de programmation empêche complètement les procédures stockées d'être réutilisables.
la source
Voici mon top 3.
Numéro 1. Échec de la spécification d'une liste de champs. (Modifier: pour éviter toute confusion: il s'agit d'une règle de code de production. Elle ne s'applique pas aux scripts d'analyse uniques - sauf si je suis l'auteur.)
devrait être
Numéro 2. En utilisant un curseur et une boucle while, quand une boucle while avec une variable de boucle fera l'affaire.
Numéro 3. DateLogic à travers les types de chaînes.
Devrait être
J'ai récemment vu un pic de "Une requête vaut mieux que deux, d'accord?"
Cette requête nécessite deux ou trois plans d'exécution différents selon les valeurs des paramètres. Un seul plan d'exécution est généré et bloqué dans le cache pour ce texte SQL. Ce plan sera utilisé quelle que soit la valeur des paramètres. Il en résulte des performances médiocres intermittentes. Il est préférable d'écrire deux requêtes (une requête par plan d'exécution prévu).
la source
Champs de mot de passe lisibles par l'homme , egad. Explicite.
Utiliser LIKE contre des colonnes indexées , et je suis presque tenté de dire LIKE en général.
Recyclage des valeurs PK générées par SQL.
Surprise, personne n'a encore mentionné la table divine. Rien ne dit "organique" comme 100 colonnes de drapeaux de bits, de grandes chaînes et des entiers.
Ensuite, il y a le modèle «Les fichiers .ini me manquent» : stockage de fichiers CSV, de chaînes délimitées par des tuyaux ou d'autres données d'analyse requises dans de grands champs de texte.
Et pour MS SQL Server, l'utilisation de curseurs du tout . Il existe une meilleure façon d'effectuer une tâche de curseur donnée.
Modifié parce qu'il y en a tellement!
la source
LIKE '%LIKE'
.Pas besoin de creuser profondément pour cela: ne pas utiliser de déclarations préparées.
la source
Utilisation d'alias de table sans signification:
Rend la lecture d'une grande instruction SQL beaucoup plus difficile qu'elle ne devrait l'être
la source
la source
Mes bugbears sont les 450 tables d'accès de colonne qui ont été rassemblées par le fils de 8 ans du meilleur toiletteur pour chiens du directeur général et la table de recherche douteuse qui n'existe que parce que quelqu'un ne sait pas normaliser correctement une infrastructure de données.
En règle générale, cette table de recherche ressemble à ceci:
J'ai perdu le compte du nombre de clients que j'ai vus qui ont des systèmes qui reposent sur des abominations comme celle-ci.
la source
Ceux que je déteste le plus sont
Utilisation d'espaces lors de la création de tableaux, de sprocs, etc. J'ai rencontré ça) m'irrite vraiment.
Données dénormalisées. Un tableau n'a pas besoin d'être parfaitement normalisé, mais lorsque je rencontre un tableau d'employés qui a des informations sur leur score d'évaluation actuel ou leur principal élément, il me dit que je devrai probablement créer un tableau séparé à un moment donné et essayez ensuite de les garder synchronisés. Je normaliserai d'abord les données, puis si je vois un endroit où la dénormalisation aide, je l'envisagerai.
Surutilisation des vues ou des curseurs. Les vues ont un but, mais lorsque chaque table est enveloppée dans une vue, c'est trop. J'ai dû utiliser des curseurs à quelques reprises, mais en général, vous pouvez utiliser d'autres mécanismes pour cela.
Accès. Un programme peut-il être un anti-modèle? Nous avons SQL Server à mon travail, mais un certain nombre de personnes utilisent l'accès en raison de sa disponibilité, de sa «facilité d'utilisation» et de sa «convivialité» pour les utilisateurs non techniques. Il y a trop de choses ici, mais si vous avez été dans un environnement similaire, vous savez.
la source
utilisez SP comme préfixe du nom de la procédure de stockage car il recherchera d'abord dans l'emplacement des procédures système plutôt que dans les personnalisées.
la source
Surutilisation des tables temporaires et des curseurs.
la source
Pour stocker les valeurs d'heure, seul le fuseau horaire UTC doit être utilisé. L'heure locale ne doit pas être utilisée.
la source
en utilisant @@ IDENTITY au lieu de SCOPE_IDENTITY ()
Cité de cette réponse :
la source
Réutiliser un champ «mort» pour quelque chose auquel il n'était pas destiné (par exemple, stocker des données utilisateur dans un champ «Fax») - très tentant cependant comme solution rapide!
la source
et en supposant que le résultat sera trié par some_column. J'ai vu cela un peu avec Sybase où l'hypothèse est vraie (pour l'instant).
la source
Ou, tout entasser en une seule ligne.
la source
La
FROM TableA, TableB WHERE
syntaxe pour JOINS plutôt queFROM TableA INNER JOIN TableB ON
Le fait de supposer qu'une requête sera renvoyée est trié d'une certaine manière sans insérer de clause ORDER BY, simplement parce que c'est ainsi qu'il est apparu lors des tests dans l'outil de requête.
la source
Apprendre le SQL au cours des six premiers mois de sa carrière et ne jamais rien apprendre d'autre au cours des 10 prochaines années. En particulier, ne pas apprendre ou utiliser efficacement les fonctionnalités de fenêtrage / analytique SQL. En particulier l'utilisation de over () et de la partition par.
Voir O'Reilly SQL Cookbook Annexe A pour un bon aperçu des fonctions de fenêtrage.
la source
Je dois mettre mon propre favori actuel ici, juste pour compléter la liste. Mon antipattern préféré ne teste pas vos requêtes .
Cela s'applique lorsque:
Et tout test exécuté contre des données atypiques ou insuffisantes ne compte pas. S'il s'agit d'une procédure stockée, mettez l'instruction de test dans un commentaire et enregistrez-la avec les résultats. Sinon, mettez-le dans un commentaire dans le code avec les résultats.
la source
Abus de table temporaire.
Plus précisément ce genre de chose:
Ne créez pas de table temporaire à partir d'une requête, uniquement pour supprimer les lignes dont vous n'avez pas besoin.
Et oui, j'ai vu des pages de code sous cette forme dans des bases de données de production.
la source
Point de vue contraire: obsession excessive de la normalisation.
La plupart des systèmes SQL / RBDB offrent de nombreuses fonctionnalités (transactions, réplication) qui sont très utiles, même avec des données non normalisées. L'espace disque est bon marché, et parfois il peut être plus simple (code plus facile, temps de développement plus rapide) de manipuler / filtrer / rechercher les données récupérées, que d'écrire le schéma 1NF, et de gérer tous les tracas qu'il contient (jointures complexes, sous-sélections désagréables , etc).
J'ai trouvé que les systèmes sur-normalisés sont souvent une optimisation prématurée, en particulier pendant les premiers stades de développement.
(plus de réflexions à ce sujet ... http://writeonly.wordpress.com/2008/12/05/simple-object-db-using-json-and-python-sqlite/ )
la source
Je viens de mettre celui-ci ensemble, basé sur certaines des réponses SQL ici sur SO.
C'est un contre-modèle sérieux de penser que les déclencheurs sont aux bases de données comme les gestionnaires d'événements le sont à la POO. Il y a cette perception que n'importe quelle ancienne logique peut être insérée dans des déclencheurs, pour être déclenchée lorsqu'une transaction (événement) se produit sur une table.
Pas vrai. L'une des grandes différences est que les déclencheurs sont synchrones - avec une vengeance, car ils sont synchrones sur une opération définie, et non sur une opération de ligne. Du côté de la POO, exactement le contraire - les événements sont un moyen efficace d'implémenter des transactions asynchrones.
la source
Procédures ou fonctions stockées sans aucun commentaire ...
la source
1) Je ne sais pas que c'est un anti-modèle "officiel", mais je n'aime pas et j'essaye d'éviter les littéraux de chaîne comme valeurs magiques dans une colonne de base de données.
Un exemple de la table 'image' de MediaWiki:
(Je remarque juste un boîtier différent, une autre chose à éviter)
Je conçois des cas tels que des recherches int dans les tableaux ImageMediaType et ImageMajorMime avec des clés primaires int.
2) conversion de date / chaîne qui repose sur des paramètres NLS spécifiques
sans identificateur de format
la source
Sous-requêtes identiques dans une requête.
la source
La vue modifiée - Une vue qui est modifiée trop souvent et sans préavis ni raison. Le changement sera soit remarqué au moment le plus inapproprié, soit pire se trompera et ne sera jamais remarqué. Peut-être que votre application sera interrompue parce que quelqu'un a pensé à un meilleur nom pour cette colonne. En règle générale, les vues devraient étendre l'utilité des tables de base tout en conservant un contrat avec les consommateurs. Résolvez les problèmes mais n'ajoutez pas de fonctionnalités ou pire changement de comportement, pour cela créez une nouvelle vue. Pour atténuer, ne partagez pas les vues avec d'autres projets et utilisez les CTE lorsque les plateformes le permettent. Si votre boutique dispose d'un DBA, vous ne pouvez probablement pas changer de vue, mais toutes vos vues seront obsolètes et / ou inutiles dans ce cas.
Le! Paramed - Une requête peut-elle avoir plusieurs objectifs? Probablement, mais la prochaine personne qui le lira ne le saura pas avant une profonde méditation. Même si vous n'en avez pas besoin maintenant, il y a de fortes chances que vous le fassiez, même si c'est "juste" pour déboguer. L'ajout de paramètres réduit le temps de maintenance et garde les choses au SEC. Si vous avez une clause where, vous devez avoir des paramètres.
Le cas sans CAS -
la source
Les deux que je trouve le plus, et qui peuvent avoir un coût significatif en termes de performances sont:
Utiliser des curseurs au lieu d'une expression basée sur un ensemble. Je suppose que celui-ci se produit fréquemment lorsque le programmeur réfléchit de manière procédurale.
À l'aide de sous-requêtes corrélées, lorsqu'une jointure à une table dérivée peut faire le travail.
la source
Placer des éléments dans des tables temporaires, en particulier les personnes qui passent de SQL Server à Oracle, ont l'habitude de trop utiliser les tables temporaires. Utilisez simplement des instructions select imbriquées.
la source
Les développeurs qui écrivent des requêtes sans avoir une bonne idée de ce qui rend les applications SQL (à la fois les requêtes individuelles et les systèmes multi-utilisateurs) rapides ou lentes. Cela comprend l'ignorance de:
la source
Utilisation de SQL comme package ISAM (méthode d'accès séquentiel indexé) glorifié. En particulier, imbriquer des curseurs au lieu de combiner des instructions SQL en une seule instruction, quoique plus volumineuse. Cela compte également comme «abus de l'optimiseur» car en fait, l'optimiseur ne peut pas faire grand-chose. Cela peut être combiné avec des déclarations non préparées pour une inefficacité maximale:
La solution correcte (presque toujours) consiste à combiner les deux instructions SELECT en une seule:
Le seul avantage de la version à double boucle est que vous pouvez facilement repérer les ruptures entre les valeurs du tableau 1 car la boucle interne se termine. Cela peut être un facteur dans les rapports de rupture de contrôle.
En outre, le tri dans l'application est généralement un non-non.
la source
Utilisation de clés primaires comme substitut pour les adresses d'enregistrement et utilisation de clés étrangères comme substitut pour les pointeurs intégrés aux enregistrements.
la source