Je suis pris dans un débat au travail et j'ai besoin de conseils sur les pièges que je pourrais ignorer.
Imaginez un scénario dans lequel un déclencheur est utilisé pour copier des enregistrements supprimés dans une table d'audit. Le déclencheur utilise SELECT *. Tout le monde pointe et crie et nous dit à quel point c'est mauvais.
Cependant, si une modification est apportée à la structure de la table principale et que la table d'audit est ignorée, le déclencheur générera une erreur permettant aux utilisateurs de savoir que la table d'audit doit également être modifiée.
L'erreur sera détectée lors des tests sur nos serveurs DEV. Mais nous devons nous assurer que les correspondances de production DEV, nous autorisons donc SELECT * dans les systèmes de production (déclencheurs uniquement).
Donc, ma question est: on me pousse à supprimer le SELECT *, mais je ne sais pas comment garantir que nous capturons automatiquement les erreurs de développement de cette nature, des idées ou est-ce la meilleure pratique?
J'ai rassemblé un exemple ci-dessous:
--Create Test Table
CREATE TABLE dbo.Test(ID INT IDENTITY(1,1), Person VARCHAR(255))
--Create Test Audit Table
CREATE TABLE dbo.TestAudit(AuditID INT IDENTITY(1,1),ID INT, Person VARCHAR(255))
--Create Trigger on Test
CREATE TRIGGER [dbo].[trTestDelete] ON [dbo].[Test] AFTER DELETE
NOT FOR REPLICATION
AS
BEGIN
SET NOCOUNT ON;
INSERT dbo.TestAudit([ID], [Person])
SELECT *
FROM deleted
END
--Insert Test Data into Test
INSERT INTO dbo.Test VALUES
('Scooby')
,('Fred')
,('Shaggy')
--Perform a delete
DELETE dbo.Test WHERE Person = 'Scooby'
MISE À JOUR (reformuler la question):
Je suis un DBA et je dois m'assurer que les développeurs ne fournissent pas de scripts de déploiement mal pensés en contribuant à notre documentation des meilleures pratiques. SELECT * provoque une erreur dans DEV lorsque le développeur ignore la table d'audit (il s'agit d'un filet de sécurité), de sorte que l'erreur est détectée au début du processus de développement. Mais quelque part dans la Constitution SQL - 2ème amendement, il est écrit "Tu ne dois pas utiliser SELECT *". Il y a donc maintenant un effort pour se débarrasser du filet de sécurité.
Comment remplacer le filet de sécurité ou devrais-je considérer que c'est la meilleure pratique pour les déclencheurs?
MISE À JOUR 2: (solution)
Merci pour toutes vos contributions, je ne suis pas sûr d'avoir une réponse claire car cela semble être un sujet très gris. Mais collectivement, vous avez fourni des points de discussion qui peuvent aider nos développeurs à avancer dans la définition de leurs meilleures pratiques.
Merci Daevin
pour votre contribution, votre réponse fournit les bases de certains mécanismes de test que nos développeurs peuvent implémenter. +1
Merci CM_Dayton
, vos suggestions contribuant aux meilleures pratiques peuvent être utiles à toute personne qui développe des déclencheurs d'audit. +1
Merci ypercube
beaucoup, vous avez beaucoup réfléchi aux problèmes concernant les tables subissant différentes formes de modifications de définition. +1
En conclusion:
Is Select * ok in a tigger?
Oui, c'est une zone grise, ne suivez pas aveuglément l'idéologie "Select * is Bad".
Am I asking for Trouble?
Oui, nous faisons plus que simplement ajouter de nouvelles colonnes aux tableaux.
la source
SELECT *
être paresseux, mais puisque vous avez une raison légitime de l'utiliser, c'est plus gris que noir et blanc. Ce que vous devriez essayer de faire est quelque chose comme ça , mais ajustez-le non seulement pour avoir le même nombre de colonnes, mais aussi pour que les noms de colonnes et les types de données soient les mêmes (car quelqu'un pourrait changer les types de données et toujours causer des problèmes dans la base de données qui ne sont pas normalement interceptés avec votreSELECT *
«filet de sécurité»SELECT *
comme filet de sécurité, mais elle n'attrapera pas tous les cas. Par exemple, si vous déposez une colonne et l'ajoutez à nouveau. Cela modifiera l'ordre des colonnes et (sauf si toutes les colonnes sont du même type), les insertions dans la table d'audit échoueront ou entraîneront une perte de données en raison des conversions implicites de types.Réponses:
En règle générale, il est considéré comme une programmation «paresseuse».
Étant donné que vous insérez spécifiquement deux valeurs dans votre
TestAudit
tableau ici, je veillerais à ce que votre sélection obtienne également exactement deux valeurs. Parce que si, pour une raison quelconque, cetteTest
table a ou obtient une troisième colonne, ce déclencheur échouera.Pas directement lié à votre question, mais si vous configurez une table d'audit, j'ajouterais également des colonnes supplémentaires à votre
TestAudit
table pour ...Cela se traduit donc par une requête comme:
De cette façon, vous obtenez les colonnes exactes dont vous avez besoin et vous auditez sur quoi / quand / pourquoi / qui est l'événement d'audit.
la source
J'ai commenté cela sur votre question, mais j'ai pensé que j'essaierais de présenter une solution de code.
Je suis généralement d'accord pour
SELECT *
être paresseux, mais comme vous avez une raison légitime de l'utiliser, c'est plus gris que noir et blanc.Ce que vous devriez (à mon avis) essayer de faire est quelque chose comme ça , mais ajustez-le pour vous assurer que les noms de colonne et les types de données sont les mêmes (car quelqu'un pourrait changer les types de données et toujours causer des problèmes dans la base de données qui ne sont pas normalement pris en compte avec votre
SELECT *
sécurité) net'.Vous pouvez même créer une fonction qui vous permettra de vérifier rapidement si la version d'audit de la table correspond à la version non audit:
Le
SELECT ... EXCEPT SELECT ...Audit
vous montrera quelles colonnes du tableau ne se trouvent pas dans le tableau d'audit. Vous pouvez même modifier la fonction pour renvoyer le nom de colonnes qui ne sont pas les mêmes au lieu de simplement mapper ou non, ou même lever une exception.Vous pouvez ensuite l'exécuter avant de passer de
DEV
auxPRODUCTION
serveurs pour chaque table de la base de données, en utilisant un curseur sur:la source
L'instruction qui signalera le déclencheur échouera et le déclencheur échouera. Il serait préférable de documenter le déclencheur et la piste d'audit afin que vous sachiez modifier la requête pour ajouter les colonnes au lieu de spécifier le *.
À tout le moins, vous devez modifier le déclencheur afin qu'il puisse échouer correctement lors de la journalisation des erreurs dans une table et peut-être placer une alerte sur la table dans laquelle le déclencheur enregistre les erreurs.
Cela vous rappelle également que vous pouvez mettre un déclencheur ou une alerte lorsque quelqu'un modifie la table et ajoute plus de colonnes ou supprime des colonnes, pour vous informer d'ajouter le déclencheur.
En termes de performances, je crois * que cela ne change rien, cela augmente simplement les risques d'échecs sur la route lorsque les choses changent et peut également provoquer une latence du réseau lorsque vous récupérez plus d'informations sur le réseau lorsque vous en avez besoin. Il y a un temps et un lieu pour *, mais je pense que comme décrit ci-dessus, vous avez de meilleures solutions et outils à essayer à la place.
la source
Si vos structures de table d'origine ou d'audit changent, vous garantissez que vous rencontrerez un problème avec votre select *.
Si l'un ou l'autre change, le déclencheur produira une erreur.
Vous pourriez faire:
Mais comme le dit CM_Dayton, c'est une programmation paresseuse et ouvre la porte à d'autres incohérences. Pour que ce scénario fonctionne, vous devez vous assurer que vous mettez à jour la structure des deux tables en même temps.
la source