web-dev-qa-db-fra.com

Quelles sont les meilleures pratiques d'écrire une procédure stockée SQL

J'ai trouvé que les procédures stockées SQL sont très intéressantes et utiles. J'ai écrit des procédures stockées, mais je veux écrire bien conçu, de bonnes performances réglées et concises SPS pour toute sorte d'exigence et j'aimerais aussi apprendre les astuces ou les bonnes pratiques pour les procédures stockées. Comment puis-je passer du débutant à l'étape avancée dans la rédaction de procédures stockées?

Mise à jour: découverte de commentaires que ma question devrait être plus spécifique. Tout le monde a des astuces sur leurs manches et que je m'attendais à de telles astuces et pratiques pour SPS qu'ils utilisent dans leur code qui les différencie des autres et plus important encore la productivité par écrit et travaillant avec des procédures stockées.

30
blntechie

Voici mes directives de traitement des erreurs de procédure stockées.

  • Appelez chaque procédure stockée à l'aide de son nom pleinement qualifié pour améliorer les performances: c'est le nom du serveur, le nom de la base de données, le nom du schéma (propriétaire) et le nom de la procédure.
  • Dans le script qui crée chaque procédure stockée, spécifiez explicitement quels rôles sont autorisés à exécuter la procédure, par exemple public ou autre.
  • Utilisez SYSMESSAGE, SP_ADDMESSAGE, ET ENTREPLOIERS PLUS DE MESSAGES D'ERREUR CODÉS DUR.
  • Lorsque vous utilisez SP_ADDMESSAGE et SYSMESSAGES, utilisez toujours le numéro de message d'erreur de 50001 ou plus.
  • Avec RaisError, fournissez toujours un niveau de gravité <= 10 pour les messages d'avertissement.
  • Avec RaisError, fournissez toujours un niveau de gravité entre 11 et 16 pour les messages d'erreur.
  • N'oubliez pas qu'utiliser Raiserror n'abandonne toujours aucun lot en cours, même dans le contexte de la gâchette.
  • Enregistrer @@ @ error à une variable locale avant de l'utiliser ou de l'interroger.
  • Enregistrer @@ RowCount à une variable locale avant de l'utiliser ou de l'interroger.
  • Pour une procédure stockée, utilisez la valeur de retour pour indiquer le succès/l'échec uniquement, pas d'autres informations supplémentaires/supplémentaires.
  • La valeur de retour d'une procédure stockée doit être définie sur 0 pour indiquer le succès, non nulle pour indiquer une défaillance.
  • SET ANSI_WARNINGS ON - Ceci détecte les valeurs NULL dans une affectation globale et toute affectation dépassant la longueur maximale d'une colonne de caractère ou de binaire.
  • Définissez Nocount sur, pour de nombreuses raisons.
  • Pensez soigneusement de savoir si vous voulez xact_abort sur ou éteint . Quelle que soit la façon dont vous allez, soyez cohérent.
  • Quittez la première erreur - cela implémente le KISS Modèle.
  • Lors de l'exécution d'une procédure stockée, vérifiez toujours à la fois @@ error et la valeur de retour. Par exemple:

    EXEC @err = AnyStoredProc @value
    SET  @save_error = @@error
    -- NULLIF says that if @err is 0, this is the same as null
    -- COALESCE returns the first non-null value in its arguments
    SELECT @err = COALESCE( NULLIF(@err, 0), @save_error )
    IF @err <> 0 BEGIN 
        -- Because stored proc may have started a tran it didn't commit
        ROLLBACK TRANSACTION 
        RETURN @err 
    END
    
  • Lors de l'exécution d'une procédure stockée locale qui entraîne une erreur, effectuez une restauration car elle est possible pour la procédure d'avoir démarré une transaction qu'elle n'a pas commis ni annulée.
  • Ne présumez pas que simplement parce que vous n'avez pas commencé une transaction, il n'y a aucune transaction active - l'appelant a peut-être en entré un.
  • Idéalement, évitez de faire la restauration sur une transaction qui a été lancée par votre appelant - alors vérifiez @@ Trancount.
  • Mais dans une gâchette, faites toujours la restauration, car vous ne savez pas si l'appelant a lancé une transaction active (car @@ TRANCOUNT est toujours> = 1).
  • Toujours stocker et vérifier @@ erreur après les affirmations suivantes:

    INSERT, DELETE, UPDATE
    SELECT INTO
    Invocation of stored procedures
    invocation of dynamic SQL
    COMMIT TRANSACTION
    DECLARE and OPEN CURSOR
    FETCH from cursor
    WRITETEXT and UPDATETEXT
    
  • Si le curseur Declare échoue sur un curseur de processus-global (la valeur par défaut), émettez une déclaration pour annouez le curseur.
  • Soyez prudent avec une erreur dans un UDF. Lorsqu'une erreur survient dans un UDF, l'exécution de la fonction est annulée immédiatement et la requête qui a appelé l'UDF - mais @@ error est 0! Vous voudrez peut-être courir avec Set Xact_Abort dans ces circonstances.
  • Si vous souhaitez utiliser Dynamic SQL, essayez d'avoir uniquement une seule sélection dans chaque lot car @@ erreur ne contient l'état de la dernière commande exécutée. Les erreurs les plus probables d'un lot de SQL dynamique sont des erreurs de syntaxe et ceux-ci ne sont pas pris en charge par définir xact_abort sur.
40
RoadWarrior

Le seul tour que j'essaie toujours d'utiliser est: Toujours inclure un exemple d'utilisation dans un commentaire près du sommet. Ceci est également utile pour tester votre SP. J'aime inclure les exemples les plus courants - alors vous n'avez même pas besoin d'une invite SQL ou d'un fichier .SQL séparé avec votre invocation préférée, car il est stocké là-bas dans le serveur (ceci est particulièrement utile si vous avez stocké les PROC qui regardent les PROC qui examinent SP_WHO SORTIE POUR LES BLOQUES OU QUELQU'UN ET QUELQUE CHANGE DE PARAMÈTRES).

Quelque chose comme:

/*
    Usage:
    EXEC usp_ThisProc @Param1 = 1, @Param2 = 2
*/

Ensuite, pour tester ou exécuter le SP, vous soulignez simplement cette section dans votre script et exécutez.

18
Cade Roux
  1. Toujours utiliser Set Nocount sur
  2. Si vous allez effectuer deux ou plusieurs inserts/mises à jour/suppressions, veuillez utiliser une transaction.
  3. Ne nommez jamais votre procs 'sp_'. SQL Server examinera d'abord dans la base de données principale, ce qui ne le trouve pas, puis regardez dans votre base de données de seconde. Si vous nommez votre Procs différemment, SQL Server examinera d'abord votre base de données.

Mauvais:

SET NOCOUNT ON
BEGIN TRAN
  INSERT...
  UPDATE...
COMMIT

Mieux, mais a l'air désordonnée et une douleur majeure à coder:

SET NOCOUNT ON
BEGIN TRAN
  INSERT...
  IF @ErrorVar <> 0
  BEGIN
      RAISERROR(N'Message', 16, 1)
      GOTO QuitWithRollback
  END

  UPDATE...
  IF @ErrorVar <> 0
  BEGIN
      RAISERROR(N'Message', 16, 1)
      GOTO QuitWithRollback
  END

  EXECUTE @ReturnCode = some_proc @some_param = 123
  IF (@@ERROR <> 0 OR @ReturnCode <> 0)
       GOTO QuitWithRollback 
COMMIT
GOTO   EndSave              
QuitWithRollback:
    IF (@@TRANCOUNT > 0)
        ROLLBACK TRANSACTION 
EndSave:

Bon:

SET NOCOUNT ON
SET XACT_ABORT ON
BEGIN TRY
    BEGIN TRAN
    INSERT...
    UPDATE...
    COMMIT
END TRY
BEGIN CATCH
    IF (XACT_STATE()) <> 0
        ROLLBACK
END CATCH

Meilleur:

SET NOCOUNT ON
SET XACT_ABORT ON
BEGIN TRAN
    INSERT...
    UPDATE...
COMMIT

Alors, où est la manipulation des erreurs sur la "meilleure" solution? Vous n'en avez pas besoin. Voir le SET XACT_ABORT ON, cela signifie effectuer un retour automatique s'il y a des erreurs. Le code est plus propre et plus facile à lire, plus facile à écrire et moins de buggy. Moins de buggy car il n'ya aucune chance de manquer une condition d'erreur car SQL Server le fait maintenant cela pour vous.

11
Simon Hughes

C'est une question très générale, mais voici quelques conseils:

  • Nommez vos procédures stockées de manière cohérente. Beaucoup utilisent un préfixe pour identifier qu'il s'agit d'une procédure stockée, mais n'utilisez pas 'sp_' comme préfixe que celle désignée pour les données principales (dans SQL Server de toute façon).
  • Définir Nocount sur, car cela réduit le nombre de valeurs de retour possibles
  • Les requêtes basées sur une installation fonctionnent souvent mieux que les curseurs. Cette question Englobe cela beaucoup plus de détails.
  • Si vous déclarez des variables pour votre procédure stockée, utilisez de bonnes conventions de nommage comme vous le feriez/devrait dans n'importe quel autre type de programmation.
  • Appelez SPS à l'aide de leur nom complet pour éliminer toute confusion sur laquelle SP doit être appelé et pour aider à renforcer les performances SQL Server; cela facilite la recherche de SP en question.

Il y a beaucoup plus, bien sûr. Voici un lien avec plus: Astuces d'optimisation des procédures SQL Server stockées

11
AR.

Dans SQL Server, j'ai toujours mis une déclaration qui supprimera la procédure si elle existe afin que je puisse facilement apporter de nouveau la procédure pendant que je le développe. Quelque chose comme:

[.____] si existe (sélectionnez * à partir de sys.objects où objet_id = objet_id (n'usp ') et tapez (N'p', N'PC ')))) 
 Drop Procédure USP 
3
Scott

Cela dépend fortement de ce que vous faites dans les Procs stockés. Cependant, il est judicieux d'utiliser des transactions si vous effectuez plusieurs inserts/mises à jour ou supprimés dans un proc. De cette façon, si une partie échoue, les autres parties sont roulées en arrière laissant votre base de données dans un état cohérent.

Les deux choses les plus importantes à prendre en compte lors de la rédaction d'une base de données (et donc lors de l'utilisation d'un PROC stocké qui effectue une action autre que SELECT) sont l'intégrité et la performance des données. Sans intégrité de données, vous avez simplement une base de données contenant des ordures et est inutile. Sans Performacne, vous n'aurez aucun utilisateur (s'ils sont en dehors des clients) ou des utilisateurs malheureux (s'ils sont mandatés d'utiliser votre produit, des utilisateurs internes n'ayant pas le choix d'aller ailleurs). Ni l'un ni l'autre n'est bon pour votre carrière. Ainsi, par écrit un PROC stocké, assurez-vous d'abord que vous vous assurez d'abord que les données seront entrées correctement dans la base de données et qu'elle échouera s'il ya un problème dans une partie de l'action.

Si besoin d'écrire des chèques dans la région pour vous assurer que votre résultat final sera correct. Je suis un spécialiste de l'ETL et j'écris toujours que mes processus pour que les données soient nettoyées et normalisées avant d'essayer de l'importer dans mes tables. Si vous faites des choses à partir de l'interface utilisateur, cela pourrait ne pas être aussi important de faire dans le PROC, bien que j'aurais que l'utilisateur Inteface vérifie avant même l'exécution de la procédure pour que les données soient bonnes pour l'insert (des choses comme la vérification pour vous assurer que Un datfield contient une date réelle que tous les champs obligatoires ont des valeurs, etc.)

Si vous écrivez des procédures pour mettre de grandes quantités de données dans des tables, il est préférable d'avoir un moyen de tester ces résultats avant qu'ils ne soient finalisés. Vous seriez étonné de la malbouffe, vous obtiendrez des clients et des fournisseurs pour les importations de données. Nous écrivons tous nos processus d'importation avec un drapeau de test. De cette façon, vous pouvez renvoyer les données Sélectionner plutôt que d'effectuer l'action afin que vous puissiez voir à l'avance, exactement ce que vous affecteriez.

Je ne suis pas un fan de SQL dynamique et je préfère ne pas l'utiliser dans des Procs stockés. Si vous êtes bloqué avec Dynamic SQL dans les Procs existants, veuillez mettre un drapeau de débogage qui vous permettra d'imprimer le SQL plutôt que de l'exécuter. Ensuite, mettez dans les commentaires les cas les plus typiques que vous devrez courir. Vous constaterez que vous pouvez maintenir le produit beaucoup mieux si vous faites cela.

Ne faites pas les choses dans un curseur, vous voulez juste que vous souhaitez réutiliser un autre Proc stocké qui ne fonctionne que sur un seul disque à l'heure. La réutilisation du code qui provoque des problèmes de performance si une mauvaise chose.

Si vous utilisez des relevés de cas ou si des déclarations, assurez-vous d'avoir effectué des tests qui frapperont toutes les branches possibles. Celui que vous ne testez pas est celui qui échouera.

2
HLGEM

Ce n'est pas une question qui peut être répondu directement sans plus d'informations, mais quelques règles générales appliquent vraiment.

Les procédures stockées sont simplement des requêtes T-SQL qui sont stockées. Par conséquent, devenir plus familier avec T-SQL et les différentes fonctions et syntaxes est vraiment ce que vous devez faire. Et encore plus d'un point de vue de la performance, vous devrez vous assurer que vos requêtes et les structures de données sous-jacentes correspondent de manière à permettre une bonne performance. IE, garantir que les indices, les relations, les contraintes, etc. sont mis en œuvre si nécessaire.

Comprendre comment utiliser les outils de réglage de la performance, sous-estimation de la manière dont les plans d'exécution fonctionnent et les choses de cette nature sont la manière dont vous arrivez à ce "niveau supérieur"

1
Mitchel Sellers

Avec SQL Server 2008, utilisez l'essai ... Construit de Catch, que vous pouvez utiliser dans vos procédures stockées T-SQL pour fournir un mécanisme plus gracieux pour la gestion des exceptions que prévu dans les versions précédentes de SQL Server en cochant @@ error (et souvent l'utilisation des déclarations de goto) après chaque relevé SQL.

         BEGIN TRY
             one_or_more_sql_statements
         END TRY
         BEGIN CATCH
             one_or_more_sql_statements
         END CATCH

Lorsque dans un bloc de capture, vous pouvez utiliser les fonctions d'erreur suivantes pour capturer des informations sur l'erreur qui a appelé le bloc de capture,

         ERROR_NUMBER()
         ERROR_MESSAGE()
         ERROR_SEVERITY()
         ERROR_STATE()
         ERROR_LINE()
         ERROR_PROCEDURE()

Contrairement à @@ Erreur, qui est réinitialisé par chaque instruction exécutée, les informations d'erreur récupérées par les fonctions d'erreur restent constantes n'importe où dans le cadre du bloc de capture d'un essai ... Déclaration de capture. Ces fonctions pourraient permettre de modulariser la manipulation des erreurs dans une seule procédure afin de ne pas avoir à répéter le code de manipulation des erreurs dans chaque bloc de capture.

1
nk2

Voici quelques meilleures pratiques,

  1. Évitez le préfixe _SP
  2. Inclure ensemble nocount sur la déclaration
  3. Essayez d'éviter d'utiliser la table Temp
  4. Essayez d'éviter d'utiliser SELECT * à partir de
  5. Essayez d'éviter d'utiliser le curseur
  6. utilisez une indexation appropriée
  7. Traitement d'erreur appropriée

Pour plus d'explications et d'échantillons de code T-SQL, veuillez consulter cet article

0
nagnath

Voici un seul code pour prouver qu'il n'y a pas de rentachements à plusieurs niveaux sur SQL Server et il illustre comment les transactions sont traitées:


BEGIN TRAN;

    SELECT @@TRANCOUNT AS after_1_begin;

BEGIN TRAN;

    SELECT @@TRANCOUNT AS after_2_begin;

COMMIT TRAN;

    SELECT @@TRANCOUNT AS after_1_commit;

BEGIN TRANSACTION;

    SELECT @@TRANCOUNT AS after_3_begin;

ROLLBACK TRAN;

    SELECT @@TRANCOUNT AS after_rollback;
0
darlove

Stuff basique:

Avoir une stratégie de traitement des erreurs et des erreurs de piège sur toutes les déclarations SQL.
[.____] décider d'une politique d'utilisation du contrôle de code source pour les procédures stockées.
[.____] Inclure un en-tête commenté avec l'utilisateur, la date/heure et le but de la SP.
Rendez-vous explicitement 0 (succès) pour une exécution réussie, autre chose autrement.
Pour les procédures non triviales, incluez un cas de test (ou des cas) et une description du résultat attendu.
[.____] Obtenir l'habitude des tests de performance. Pour les cas de texte, le temps d'exécution enregistré au moins.
Comprendre des transactions explicites et les utiliser.
N'appellez presque jamais SPS de SPS. La réutilisabilité est une balle différente avec SQL.

0
dkretz