Multi-déclaration de la Fonction à valeur de Table vs Inline Fonction à valeur de Table
Quelques exemples pour montrer, juste au cas où:
Inline Table
CREATE FUNCTION MyNS.GetUnshippedOrders()
RETURNS TABLE
AS
RETURN SELECT a.SaleId, a.CustomerID, b.Qty
FROM Sales.Sales a INNER JOIN Sales.SaleDetail b
ON a.SaleId = b.SaleId
INNER JOIN Production.Product c ON b.ProductID = c.ProductID
WHERE a.ShipDate IS NULL
GO
Multi Déclaration Table
CREATE FUNCTION MyNS.GetLastShipped(@CustomerID INT)
RETURNS @CustomerOrder TABLE
(SaleOrderID INT NOT NULL,
CustomerID INT NOT NULL,
OrderDate DATETIME NOT NULL,
OrderQty INT NOT NULL)
AS
BEGIN
DECLARE @MaxDate DATETIME
SELECT @MaxDate = MAX(OrderDate)
FROM Sales.SalesOrderHeader
WHERE CustomerID = @CustomerID
INSERT @CustomerOrder
SELECT a.SalesOrderID, a.CustomerID, a.OrderDate, b.OrderQty
FROM Sales.SalesOrderHeader a INNER JOIN Sales.SalesOrderHeader b
ON a.SalesOrderID = b.SalesOrderID
INNER JOIN Production.Product c ON b.ProductID = c.ProductID
WHERE a.OrderDate = @MaxDate
AND a.CustomerID = @CustomerID
RETURN
END
GO
Est-il un avantage à l'utilisation d'un seul type (en ligne ou multi déclaration) sur l'autre? Est-t-il des scénarios lorsque l'une est meilleure que l'autre ou les différences sont purement syntaxiques? Je me rends compte que les deux exemples de requêtes sont en train de faire différentes choses, mais est-il une raison pour laquelle je voudrais écrire de cette façon?
Lire à leur sujet, et les avantages et les différences n'ont pas été expliquées.
Aussi l'un des énormes avantages de la fonction en ligne est que vous pouvez choisir ROWID(TIMESTAMP) colonnes, tandis que vous ne pouvez pas insérer de données TIMESTAMP à la table de retour dans les instructions multiples fonctions!
Merci pour un excellent thread. J'ai appris beaucoup de choses. Cependant, une chose à garder à l'esprit lors de la modification d'une fonction qui a été ITV à MSTV, le profileur pense que vous êtes la modification d'une ITV. Peu importe ce que vous faites pour obtenir la syntaxe de droit à partir d'une ZONE de point de vue, le recompiler échoue toujours, généralement autour de la première instruction après avoir COMMENCER. La seule façon de contourner ce problème est d'abandonner la vieille de la fonction et de CRÉER le nouveau MSTV.
Merci pour un excellent thread. J'ai appris beaucoup de choses. Cependant, une chose à garder à l'esprit lors de la modification d'une fonction qui a été ITV à MSTV, le profileur pense que vous êtes la modification d'une ITV. Peu importe ce que vous faites pour obtenir la syntaxe de droit à partir d'une ZONE de point de vue, le recompiler échoue toujours, généralement autour de la première instruction après avoir COMMENCER. La seule façon de contourner ce problème est d'abandonner la vieille de la fonction et de CRÉER le nouveau MSTV.
OriginalL'auteur AndrewC | 2010-03-31
Vous devez vous connecter pour publier un commentaire.
Dans la recherche de Matt commentaire, j'ai révisé mon original de la déclaration. Il est correct, il y aura une différence de performances entre une ligne de la fonction table (ITVF) et un multi-déclaration de la fonction table (MSTVF) même si ils simplement exécuter une instruction SELECT. SQL Server traiter une ITVF un peu comme un
VIEW
en ce qu'elle permettra de calculer un plan d'exécution en utilisant les statistiques les plus récentes sur les tableaux en question. Un MSTVF est équivalent à la farce de la totalité du contenu de votre instruction SELECT dans une table variable, puis de rejoindre. Ainsi, le compilateur ne peut pas utiliser les statistiques de la table sur les tables de la MSTVF. Donc, toutes choses étant égales par ailleurs, (ce qui arrive rarement), l'ITVF sera mieux que la MSTVF. Dans mes tests, la différence de performances en temps de réalisation a été négligeable, cependant, d'un point de vue statistique, il a été perceptible.Dans votre cas, les deux fonctions ne sont pas fonctionnellement équivalent. La ZONE de fonction ne une requête supplémentaire à chaque fois qu'il est appelé et, plus important encore, les filtres sur l'id de client. Dans une grande requête, l'optimiseur ne serait pas en mesure de tirer parti d'autres types de jointures, comme il serait nécessaire d'appeler la fonction pour chaque customerId passé. Toutefois, si vous ré-écrit votre ZONE de fonction comme ceci:
Dans une requête, l'optimiseur va être en mesure d'appeler cette fonction à la fois et de construire un meilleur plan d'exécution, mais il ne serait pas encore mieux qu'un équivalent, non paramétrée ITVS ou un
VIEW
.ITVFs doit être préférée à une MSTVFs lorsque cela est possible parce que les types de données, la possibilité de valeur null et classement dans les colonnes de la table alors que vous déclarez ces propriétés dans un environnement multi-déclaration de la fonction à valeur de table et, surtout, vous obtiendrez de meilleurs plans d'exécution de l'ITVF. Dans mon expérience, je n'ai pas trouvé de nombreuses circonstances où un ITVF était une meilleure option que d'un point de VUE, mais le kilométrage peut varier.
Merci à Matt.
Plus
Depuis que j'ai vu ce sont en place récemment, voici une excellente analyse faite par Wayne Sheffield en comparant la différence de performances entre Inline fonctions à valeur de Table et Multi-Déclaration de fonctions.
Son blog original.
Copie sur SQL Serveur Central
La meilleure explication que j'ai jamais trouvé est dans la première réponse, et la related post: stackoverflow.com/questions/4109152/... Ne manquez pas le document connexe, vous pouvez le lire rapidement, et c'est très intéressant.
Il y aura une mise à jour de cette réponse pour SQL Server 2017?: youtube.com/watch?time_continue=2&v=szTmo6rTUjM
OriginalL'auteur Thomas
En interne, SQL Server traite une ligne de la fonction table comme il l'aurait vue et traite un multi-déclaration de la fonction à valeur de table similaire à la façon dont il serait une procédure stockée.
Lorsqu'une fonction table en ligne est utilisé dans le cadre d'une requête externe, le processeur de requêtes développe l'UDF définition et génère un plan d'exécution qui accède à des objets sous-jacents, à l'aide de l'index sur ces objets.
Pour un multi-déclaration de la fonction à valeur de table, un plan d'exécution est créée pour la fonction elle-même et stockées dans le cache de plan d'exécution (une fois que la fonction a été exécutée la première fois). Si le multi-déclaration de la table des fonctions utilisées dans le cadre des grandes des requêtes, l'optimiseur ne sais pas ce que la fonction retourne, et fait en sorte que certains des hypothèses standard - en effet, il suppose que la fonction retourne une seule ligne, et que le rendement de la fonction sera accessible à l'aide d'une analyse de table sur une table avec une seule ligne.
Où multi-déclaration de fonctions à valeur de table peuvent exécuter mal, c'est quand ils reviennent d'un grand nombre de lignes, et sont reliés à l'encontre de requêtes externes. Les problèmes de performances sont principalement le fait que l'optimiseur va produire un plan en supposant qu'une seule ligne est renvoyé, ce qui ne sera pas nécessairement la plus appropriée le plan.
Comme une règle générale, nous avons constaté que, si possible inline fonctions à valeur de table doit être utilisée de préférence à multi-déclaration (lorsque l'UDF sera utilisé dans le cadre d'une requête externe) en raison de ces problèmes de performances potentiels.
Sauf si vous avez besoin de joindre ces résultats dans une autre requête.
pourquoi ne pas utiliser les deux? Une procédure stockée qui renvoie le résultat d'un multi-déclaration de la fonction table. Le meilleur des deux mondes.
OriginalL'auteur Paul McLoughlin
Il y a une autre différence. Une fonction table en ligne peuvent être insérées, mises à jour et supprimées de - tout comme d'un point de vue. Des restrictions similaires s'appliquent - impossible de mettre à jour les fonctions à l'aide des agrégats, impossible de mettre à jour les colonnes calculées, et ainsi de suite.
OriginalL'auteur Craig Beere
Vos exemples, je pense, répondre à la question très bien. La première fonction peut être fait comme une sélection unique, et est une bonne raison pour utiliser le style en ligne. La seconde pourrait probablement être fait en une seule instruction (à l'aide d'une sous-requête pour obtenir le max de date), mais certains codeurs peuvent trouver plus facile de lire ou de plus naturel de le faire dans plusieurs états comme vous l'avez fait. Certaines fonctions de la plaine ne peut pas se faire en une seule instruction, et exigent le multi-compte de résultat.
Je suggère d'utiliser le plus simple (inline) chaque fois que possible, et en utilisant le multi-états lorsque c'est nécessaire (bien évidemment) ou lors de vos préférences personnelles et la lisibilité rend wirth la saisie de texte supplémentaire.
Je ne sais pas, mais je ne pense pas. Il est probablement préférable de laisser sql server figure les optimisations que vous pourriez essayer de le faire manuellement (en utilisant des variables, les tables temporaires, ou quoi que ce soit). Bien que vous pourriez certainement faire quelques tests de performance pour prouver/infirmer ce dans des cas spécifiques.
Encore un grand merci. Je peux chercher plus loin que ça quand j'aurai plus de temps! 🙂
OriginalL'auteur Ray
regarder La comparaison en ligne et Multi-Déclaration des Fonctions Table vous pouvez trouver de bonnes descriptions et des tests de performances,
OriginalL'auteur hmfarimani
Je n'ai pas testé, mais un multi fonction des caches de l'ensemble de résultats. Il peut y avoir des cas où il y a trop à faire pour que l'optimiseur aux commandes de la fonction. Par exemple, supposons que vous avez une fonction qui renvoie un résultat à partir de différentes bases de données en fonction de ce que vous transmettez en tant que "Numéro d'Entreprise". Normalement, vous pouvez créer une vue avec un union all puis filtrer par numéro d'entreprise, mais j'ai trouvé que, parfois, sql server tire l'ensemble de l'union et n'est pas assez intelligent pour appeler la sélection. Une fonction de table peut avoir une logique de choisir la source.
OriginalL'auteur William Egge
Un autre cas d'utilisation d'une ligne multi fonction serait de contourner sql server à partir de pousser vers le bas la clause where.
Par exemple, j'ai une table avec une table des noms et certains noms de table sont formatés comme C05_2019 et C12_2018 et, et tous les tableaux formatés qui ont le même schéma. Je voulais fusionner toutes ces données dans un tableau et d'analyser les 05 et 12 pour un CompNo colonne et 2018,2019 dans une colonne d'année. Cependant, il y a d'autres tables comme ACA_StupidTable que je ne peux pas extraire CompNo et CompYr et obtenez une erreur de conversion si j'ai essayé. Donc, ma question est en deux partie, une requête interne qui a retourné seulement les tableaux formatés comme 'C_______"alors que l'extérieur de la requête n'a une sous-chaîne et int de conversion. ie Cast(Substring(2, 2) comme int) CompNo. Tout a l'air bon, sauf que sql server a décidé de mettre ma fonction de distribution avant que les résultats ont été filtrés et si je reçois un esprit de brouillage erreur de conversion. Un multi déclaration de la table de fonction peut empêcher cela de se produire, puisque, fondamentalement, c'est un "nouveau" de la table.
OriginalL'auteur William Egge
si vous allez faire une requête, vous pouvez joindre à votre Table en ligne une fonction comme:
il va engager peu de surcharge et de fonctionner correctement.
si vous essayez d'utiliser votre Multi Déclaration de la Table dans une requête similaire, vous aurez des problèmes de performances:
parce que vous allez exécuter la fonction 1 fois pour chaque ligne retournée, comme le jeu de résultats est grande, il sera plus lent et plus lent.
Non, ils reviennent tous les deux à une table, ce qui rend votre deuxième SQL invalide que vous êtes en train de mettre un tableau dans une colonne.
J'ai mis à jour la requête yo commenté. les paramètres de la fonction utilisée dans la deuxième fonction, prêtent à être utilisé comme une sous-requête, ce qui entraînera une dégradation des performances.
+1 ça Sonne bien pour moi.
OriginalL'auteur KM.