Fonctions vs procédures stockées

88

Disons que je dois implémenter un morceau de code T-SQL qui doit renvoyer une table en résultat. Je peux implémenter une fonction table ou bien une procédure stockée qui renvoie un ensemble de lignes. Que dois-je utiliser?

En bref, ce que je veux savoir, c'est:

Quelles sont les principales différences entre les fonctions et les procédures stockées? Quelles considérations dois-je prendre en compte pour utiliser l'un ou l'autre?

Auron
la source
1
Cela semble être la réponse parfaite: stackoverflow.com/a/1179778/365188
Ozair Kafray

Réponses:

51

Si vous êtes susceptible de vouloir combiner le résultat de ce morceau de code avec d'autres tables, alors évidemment une fonction table vous permettra de composer les résultats dans une seule instruction SELECT.

Généralement, il existe une hiérarchie (Affichage <Fonction TV <Proc stocké). Vous pouvez en faire plus dans chacun d'eux, mais la capacité à composer les sorties et à permettre à l'optimiseur de s'impliquer vraiment diminue à mesure que la fonctionnalité augmente.

Utilisez donc celui qui vous permet au minimum d'exprimer le résultat souhaité.

Damien_The_Unbeliever
la source
50

Les fonctions doivent être déterministes et ne peuvent pas être utilisées pour apporter des modifications à la base de données, alors que les procédures stockées vous permettent de faire des insertions et des mises à jour, etc.

Vous devez limiter votre utilisation des fonctions, car elles posent un énorme problème d'évolutivité pour les requêtes volumineuses et complexes. Ils deviennent une sorte de "boîte noire" pour l'optimiseur de requêtes, et vous verrez d'énormes différences de performances entre l'utilisation de fonctions et l'insertion simple du code dans une requête.

Mais ils sont certainement utiles pour les retours table dans des cas très spécifiques.

Si vous avez besoin d'analyser une liste délimitée par des virgules, pour simuler le passage d'un tableau à une procédure, une fonction peut transformer la liste en table pour vous. C'est une pratique courante avec Sql Server 2005, car nous ne pouvons pas encore passer de tables à des procédures stockées (nous le pouvons avec 2008).

Eric Z Beard
la source
1
Mais vous POUVEZ envoyer du XML à une procédure stockée: stackoverflow.com/questions/144550/…
cllpse
2
Erreur, la plupart des fonctions du serveur SQL ne sont pas déterministes, comme getdate dans le serveur MS-SQL. Seules les fonctions ODBC sont des fonctions canoniques (= beaucoup plus rapides + indexables) ... Mais vous avez tout à fait raison, il faut limiter au maximum l'utilisation des fonctions dans les requêtes pour des raisons de performances.
Stefan Steiger
45

À partir de la documentation :

Si une procédure stockée répond aux critères suivants, elle est un bon candidat pour être réécrite en tant que fonction table:

  • La logique est exprimable dans une seule instruction SELECT, mais est une procédure stockée, plutôt qu'une vue, uniquement en raison du besoin de paramètres.

  • La procédure stockée n'effectue pas d'opérations de mise à jour, à l'exception des variables de table.

  • Il n'y a pas besoin d'instructions EXECUTE dynamiques.

  • La procédure stockée renvoie un jeu de résultats.

  • L'objectif principal de la procédure stockée est de générer des résultats intermédiaires qui doivent être chargés dans une table temporaire, qui est ensuite interrogée dans une instruction SELECT.

Christoffer Lette
la source
12

Je vais écrire quelques différences intéressantes entre les procédures stockées et les fonctions.

  • Nous pouvons utiliser des fonctions dans les requêtes de sélection, mais nous ne pouvons pas utiliser de procédures stockées dans les requêtes de sélection.
  • Nous ne pouvons pas utiliser de fonctions non déterministes dans Functions mais nous pouvons utiliser des fonctions non déterministes dans les procédures stockées. Maintenant, la question se pose, quelle est la fonction non déterministe. La réponse est: -

    Une fonction non déterministe est cette fonction qui renvoie différentes sorties pour les mêmes valeurs d'entrée à des moments différents, comme getdate (). Il renvoie toujours une valeur différente chaque fois qu'il est exécuté.

    Exception:-

    Les versions antérieures du serveur sql antérieures à sql 2000 ne permettent pas d'utiliser la fonction getdate () dans les fonctions définies par l'utilisateur, mais la version 2005 et les versions ultérieures nous permettent d'utiliser la fonction getdate () dans une fonction définie par l'utilisateur.

    Newid () est un autre exemple de fonction non déterministe mais ne peut pas être utilisé dans les fonctions définies par l'utilisateur, mais nous pouvons l'utiliser dans une procédure stockée.

  • Nous pouvons utiliser des instructions DML (insérer, mettre à jour, supprimer) dans une procédure stockée, mais nous ne pouvons pas utiliser d'instructions DML dans des fonctions sur des tables physiques ou des tables permanentes. Si nous voulons faire une opération DML dans des fonctions, nous pouvons le faire sur des variables de table et non sur des tables permanentes.

  • Nous ne pouvons pas utiliser la gestion des erreurs dans la fonction, mais nous pouvons effectuer la gestion des erreurs dans les procédures stockées.

Neeraj Kumar Yadav
la source
Comment se fait-il que les opérations DML soient prises en charge dans les fonctions MySQL?
Joey Pinto
@JoeyPinto. Parce que myNONsql n'est pas une plainte SQL. Bien sûr, il a des extras, mais pas les bases.
PerformanceDBA
8
  1. La procédure peut renvoyer zéro ou n valeurs alors que la fonction peut renvoyer une valeur qui est obligatoire.

  2. Les procédures peuvent avoir des paramètres d'entrée / sortie alors que les fonctions ne peuvent avoir que des paramètres d'entrée.

  3. La procédure permet de sélectionner ainsi que les instructions DML, tandis que la fonction ne permet que les instructions de sélection.

  4. Les fonctions peuvent être appelées à partir d'une procédure alors que les procédures ne peuvent pas être appelées à partir d'une fonction.

  5. L'exception peut être gérée par le bloc try-catch dans une procédure alors que le bloc try-catch ne peut pas être utilisé dans une fonction.

  6. On peut opter pour la gestion des transactions en procédure alors qu'on ne peut pas aller en fonction.

  7. Les procédures ne peuvent pas être utilisées dans une instruction select, tandis que la fonction peut être incorporée dans une instruction select.

  8. UDF (fonction définie par l'utilisateur) peut être utilisée dans les instructions SQL n'importe où dans la section WHERE/ HAVING/ SELECT, contrairement aux procédures stockées.

  9. Les UDF qui renvoient des tables peuvent être traitées comme un autre ensemble de lignes. Cela peut être utilisé dans JOINs avec d'autres tables.

  10. Les fonctions UDF en ligne peuvent être considérées comme des vues qui prennent des paramètres et peuvent être utilisées dans les opérations de JOINs et d'autres ensembles de lignes.

nathan1138
la source
6

Si vous avez une fonction, vous pouvez l'utiliser dans le cadre de votre instruction SQL, par exemple

SELECT function_name(field1) FROM table

Cela ne fonctionne pas de cette façon pour les procédures stockées.

Ilya Kochetov
la source
1
Je pense qu'il parlait de fonctions qui renvoient des valeurs de table.
wcm
1
Eh bien, je parle en général. Mais pour mon cas particulier, je suis maintenant actuellement entre une procédure stockée ou une fonction table.
Auron
5

J'ai exécuté quelques tests avec un long bit de logique, avec le même bit de code (une longue instruction SELECT) fonctionnant à la fois dans une fonction de table et une procédure stockée, et un EXEC / SELECT simple, et chacun exécuté de manière identique.

À mon avis, utilisez toujours une fonction à valeur de table plutôt qu'une procédure stockée pour renvoyer un jeu de résultats, car cela rend la logique beaucoup plus facile et lisible dans les requêtes qui les rejoignent par la suite, et vous permet de réutiliser la même logique. Pour éviter trop de problèmes de performance, j'utilise souvent des paramètres "optionnels" (c'est-à-dire que vous pouvez leur passer NULL) pour permettre à la fonction de renvoyer le jeu de résultats plus rapidement, par exemple:

CREATE FUNCTION dbo.getSitePermissions(@RegionID int, @optPersonID int, optSiteID int)
AS
RETURN 
    SELECT DISTINCT SiteID, PersonID
    FROM dbo.SiteViewPermissions
    WHERE (@optPersonID IS NULL OR @optPersonID = PersonID)
    AND (@optSiteID IS NULL OR @optSiteID = SiteID)
    AND @RegionID = RegionID

De cette façon, vous pouvez utiliser cette fonction dans de nombreuses situations différentes, et ne prenez pas un énorme impact sur les performances. Je pense que c'est plus efficace que de filtrer après:

SELECT * FROM dbo.getSitePermissions(@RegionID) WHERE SiteID = 1

J'ai utilisé cette technique dans plusieurs fonctions, parfois avec une longue liste de paramètres "optionnels" de ce type.

Paul Grimshaw
la source
4

Personnellement, j'utilise des fonctions de table lorsque tout ce que je retourne est une seule table sans effet. En gros, je les traite comme des vues paramétrées.

Si j'ai besoin de renvoyer plusieurs jeux d'enregistrements ou s'il y aura des valeurs mises à jour dans les tables, j'utilise une procédure stockée.

Mes 2 cents

wcm
la source
4

Comme mentionné ci-dessus, les fonctions sont plus lisibles / composables / auto-documentées, mais sont moins performantes en général, et peuvent être sérieusement moins performantes si vous vous laissez emporter par elles dans des jointures telles que

SELECT *
FROM dbo.tvfVeryLargeResultset1(@myVar1) tvf1
INNER JOIN dbo.tvfVeryLargeResultset1(@myVar2) tvf2
    ON (tvf1.JoinId = tvf2.JoinId)

Souvent, il suffit d'accepter la redondance de code qu'un tvf pourrait éliminer (à un coût de performance inacceptable).

Un autre point que je n'ai pas encore vu mentionné est que vous ne pouvez pas utiliser de tables temporaires de changement d'état de base de données à l'intérieur d'un tvf multi-instruction. Le mécanisme le plus fonctionnellement équivalent à une table temporaire est le changement non d'état, dans la variable de table mémoire, et pour les grands ensembles de données, une table temporaire sera probablement plus performante qu'une variable de table. (D'autres alternatives incluent les tables dynamiques et les expressions communes à valeur de table, mais à un certain niveau de complexité, celles-ci cessent d'être une bonne option IMO.)

6eorge Jetson
la source
1

Je testerais les deux performances. Il est probable que l'approche sp ou une table dérivée serait beaucoup plus rapide qu'une fonction et si c'est le cas, cette approche devrait être utilisée. En général, j'évite les fonctions car elles peuvent être des porcs de performance.

HLGEM
la source
1

Cela dépend :) Si vous souhaitez utiliser le résultat table dans une autre procédure, il vaut mieux utiliser une fonction TableValued. Si les résultats sont pour un client, la procédure stockée est généralement la meilleure solution.

edosoft
la source
-1

Les procédures stockées sont des requêtes pré-compilées qui s'exécutent plus rapidement et enregistrent des injections SQL. Ils peuvent renvoyer des valeurs 0 ou N. Nous pouvons effectuer des opérations DML à l'intérieur des procédures stockées. Nous pouvons utiliser des fonctions à l'intérieur des procédures et utiliser des fonctions dans la requête de sélection. Les fonctions sont utilisées pour renvoyer n'importe quelle valeur et les opérations DML ne sont pas possibles dans les fonctions. les fonctions sont de deux types scalaires et table. La fonction scalaire renvoie une valeur unique, une fonction table utilisée pour renvoyer des lignes de tables.

Harish Madaan
la source
C'est une question très ancienne avec un grand nombre de réponses, beaucoup d'entre elles (y compris la réponse acceptée) sont fortement votées. Avant d'ajouter une autre réponse à un tel fil, vous devriez vous demander, "qu'est-ce qui manque à toutes ces réponses existantes qui m'obligent à en écrire une autre?"
APC