IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

MS SQL Server Discussion :

Performance et compilation des fonctions


Sujet :

MS SQL Server

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    332
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Juin 2002
    Messages : 332
    Points : 502
    Points
    502
    Par défaut Performance et compilation des fonctions
    Bonjour,

    Je révise le code d'un développeur junior et je vois cette fonction:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    ALTER FUNCTION [dbo].[RM_GetAvgDaysToPay] 
    (
    	-- Add the parameters for the function here
    	@CompanyID int
    )
    RETURNS float
    AS
    BEGIN
    	-- Declare the return variable here
    	DECLARE @AvgDaysToPay float
     
    	-- Add the T-SQL statements to compute the return value here
    	DECLARE @Ansonia float
    	DECLARE @Freight float
     
    	SET @Ansonia = (SELECT TOP(1) aci.AvgDaysToPay FROM AnsoniaCreditInfo aci INNER JOIN CompanyDocketNumbers cdn ON aci.DocketPrefix = cdn.Prefix AND aci.DocketNumber = cdn.DocketNumber WHERE cdn.CompanyID = @CompanyID AND cdn.Purpose IN (1,3) ORDER BY cdn.Purpose)
     
    	SET @Freight = (SELECT TOP(1) ci.AvgDaysToPay FROM CreditInformation ci INNER JOIN CompanyDocketNumbers cdn ON ci.DocketPrefix = cdn.Prefix AND ci.DocketNumber = cdn.DocketNumber WHERE cdn.CompanyID = @CompanyID AND ci.DocketNumber IS NOT NULL AND ci.DocketPrefix IS NOT NULL AND cdn.Purpose IN (1,3) ORDER BY cdn.Purpose)
     
    	SET @AvgDaysToPay =
    		CASE
    			WHEN @Ansonia IS NULL AND @Freight IS NULL THEN NULL
    			WHEN @Ansonia IS NOT NULL AND @Freight IS NOT NULL THEN CONVERT(float,(@Ansonia + @Freight)) / 2
    			WHEN @Ansonia IS NOT NULL THEN @Ansonia
    			WHEN @Freight IS NOT NULL THEN @Freight
    		END
     
    	-- Return the result of the function
    	RETURN @AvgDaysToPay
     
    END
    Je me dis, plutôt que de lancer 2 requêtes et placer des valeurs en mémoire, je vais faire un seule et unique requête:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    ALTER FUNCTION [dbo].[RM_GetAvgDaysToPay2] 
    (
    	-- Add the parameters for the function here
    	@CompanyID int
    )
    RETURNS float
    AS
    BEGIN
    	RETURN 
    	(	SELECT TOP 1 CASE
    					WHEN aci.AvgDaysToPay IS NULL OR ci.AvgDaysToPay IS NULL THEN (ISNULL(aci.AvgDaysToPay, 0) + ISNULL(ci.AvgDaysToPay, 0))
    					ELSE (aci.AvgDaysToPay + ci.AvgDaysToPay) / 2
    				END AS AvgValue
    		FROM CompanyDocketNumbers cdn 
    		LEFT JOIN AnsoniaCreditInfo aci ON cdn.DocketNumber = aci.DocketNumber AND cdn.Prefix = aci.DocketPrefix
    		LEFT JOIN CreditInformation ci ON cdn.DocketNumber = ci.DocketNumber AND cdn.Prefix = ci.DocketPrefix
    		WHERE cdn.CompanyID = @CompanyID
    		AND cdn.Purpose IN (1,3) 
    		ORDER BY cdn.Purpose)
     
    END
    Je lance les fonctions côte-à-côte en utilisant les bon vieux:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    SET STATISTICS IO ON
    SET STATISTICS TIME ON
    1 - Les deux plans d'exécution sont identiques
    2 - Les statistiques de TIME et IO sont à toute fin pratique semblables

    Mon environnement:

    Instance SQL Server 2008R2
    Base en mode 90 (2005)

    Ma question:

    Est-ce que SQL Server arrive à optimiser le code des fonctions (et procédure stockées) à un point tel qu'il peut joindre deux requêtes distinctes en une seule?

    Ou bien c'est mon optimisation 'manuelle' qui n'est pas bonne?

    Je travaille avec MSSQL depuis la version 7 et j'ai peut-être des habitudes d'optmisation qui sont devenue superflues depuis.

    Merci de m'éclairer à ce sujet.

    Aussi, si vous avez des sources intéressantes sur la façon sont MSSQL compile les fonctions et l'évolution de ce processus depuis la version 7, j'apprécierais énormément.

  2. #2
    Membre éprouvé
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Août 2009
    Messages
    623
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Administrateur de base de données

    Informations forums :
    Inscription : Août 2009
    Messages : 623
    Points : 1 049
    Points
    1 049
    Par défaut
    Bonjour,
    Il faut éviter de faire des select dans des fonctions scalaires. Ta requête sera exécutée à chaque ligne. C'est totalement contre performant. Soit tu peux faire une fonction table soit une jointure.
    Concernant ta question, je n'ai plus le temps de te répondre, je viens de recevoir une demande urgente désolé...
    Blog Perso | Kankuru (logiciel gratuit pour SQL Server)

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    332
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Juin 2002
    Messages : 332
    Points : 502
    Points
    502
    Par défaut
    Citation Envoyé par darkelend Voir le message
    Bonjour,
    Il faut éviter de faire des select dans des fonctions scalaires. Ta requête sera exécutée à chaque ligne. C'est totalement contre performant. Soit tu peux faire une fonction table soit une jointure.
    Concernant ta question, je n'ai plus le temps de te répondre, je viens de recevoir une demande urgente désolé...
    C'est bon à savoir. Depuis 2007, je n'ai utilisé que des ORM pour l'accès aux données alors mes souvenirs de l'utilisation de procédures stockées et fonctions sont plutôt vagues.

    Mon réflexe serait de tout migrer vers LINQ + Entity Framework comme pour le reste du projet...

  4. #4
    Membre éprouvé
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Août 2009
    Messages
    623
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Administrateur de base de données

    Informations forums :
    Inscription : Août 2009
    Messages : 623
    Points : 1 049
    Points
    1 049
    Par défaut
    Citation Envoyé par Babyneedle Voir le message
    Mon réflexe serait de tout migrer vers LINQ + Entity Framework comme pour le reste du projet...
    Pour moi en terme de performance, je dirais que l'idéal serait procédures stockées dans la base de données + ADO.NET ou LINQ et entity pour les exécuter. Mais il faut se méfier d'entity car si tu lui demandes de faire n'importe quoi, il le fera
    Blog Perso | Kankuru (logiciel gratuit pour SQL Server)

  5. #5
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 772
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 772
    Points : 52 737
    Points
    52 737
    Billets dans le blog
    5
    Par défaut
    Contrairement à une pure requête SQL, les fonction de sont jamais optimisable. En effet, une requête est optimisable car SQL possède des statistiques de distribution des données pour chaque table et chaque index. Il peut donc faire des simplification en estimant à l'avance (avant d'exécuter) qu'utiliser tel algorithme ou lire tel ou tel index sera plus performant... Mais il est en revanche impossible de prédire quel sera le résultat d'une fonction... C'est pourquoi pour toute fonction SQL Server donne une évaluation de coût qui est toujours la même et ne dépend pas du coup réel de l'exploitation de cette fonction.
    Les coûts de requête à base d'UDF sont donc toujours faux et les UDF constituent en fait de véritables "tous noirs" pour l'optimisation, donnant ainsi l'illusion que la façon d’écrire importe peu...
    Comme le dit Darkelend, c'est à éviter... Mais il y a bien pire... Les ORM en particulier !

    À me lire : http://sqlpro.developpez.com/cours/b...s-epaisses.pdf

    A +
    Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
    Le site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Blog SQL, SQL Server, SGBDR : http://blog.developpez.com/sqlpro
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Entreprise SQL SPOT : modélisation, conseils, audit, optimisation, formation...
    * * * * * Expertise SQL Server : http://mssqlserver.fr/ * * * * *

  6. #6
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    332
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Juin 2002
    Messages : 332
    Points : 502
    Points
    502
    Par défaut
    Citation Envoyé par SQLpro Voir le message
    Contrairement à une pure requête SQL, les fonction de sont jamais optimisable. En effet, une requête est optimisable car SQL possède des statistiques de distribution des données pour chaque table et chaque index. Il peut donc faire des simplification en estimant à l'avance (avant d'exécuter) qu'utiliser tel algorithme ou lire tel ou tel index sera plus performant... Mais il est en revanche impossible de prédire quel sera le résultat d'une fonction... C'est pourquoi pour toute fonction SQL Server donne une évaluation de coût qui est toujours la même et ne dépend pas du coup réel de l'exploitation de cette fonction.
    Les coûts de requête à base d'UDF sont donc toujours faux et les UDF constituent en fait de véritables "tous noirs" pour l'optimisation, donnant ainsi l'illusion que la façon d’écrire importe peu...
    Comme le dit Darkelend, c'est à éviter... Mais il y a bien pire... Les ORM en particulier !

    À me lire : http://sqlpro.developpez.com/cours/b...s-epaisses.pdf

    A +
    Premièrement, merci pour les réponses. Effectivement, ça donne l'impression de trous noirs et c'est pour moi une raison suffisante pour les bannir.

    Si on ne tient compte que de la perspective DBA, c'est vrai que les ORM c'est l'enfer. C'est souvent une permission implicite à faire n'importe quoi.

    Par contre, je ne suis pas d'accord quand on regarde l'ensemble du tableau. Pour avoir essayé plusieurs approches, je ne crois pas pouvoir me passer des ORM pour les raisons suivantes:

    - Il ne fait aucun sens de compliquer le code pour les outils internes qui ne nécessitent pas de performance, par exemple des outils web qui servent à changer de la configuration.

    - Les ORM permettent l'utilisation d'outils et patterns qui n'existent pas au niveau BD. Par exemple, pour nos recherches intensives à partir du site web, nous avons ajouté une couche d'interception (Windsor Castle) qui nous permet de redéfinir le support de données au runtime selon l'origine géographique de la requête. Ça rend les scénarios de caches, de support map/reduce et de CDN beaucoup plus flexibles. Au niveau sharding, MSSQL n'a pas suivi la parade.

    - Dans le contexte de ressources humaines à Montréal au Canada, les DBA d'expériences sont rares, très rares. Alors il faut déléguer de la responsaiblité à des developpeurs.

    - J'ai essayé quelques frameworks de tests unitaires pour MSSQL mais nous sommes encore loin (à moins que je me trompe) de ce qui existe pour le code au niveau de l'implémentation et de l'intégration à TFS par exemple. L'utilisation d'ORM permet un code coverage plus grand.

Discussions similaires

  1. Réponses: 5
    Dernier message: 31/01/2012, 15h01
  2. Réponses: 2
    Dernier message: 15/06/2011, 14h51
  3. Performance des fonction de chaine
    Par octal dans le forum Qt
    Réponses: 3
    Dernier message: 01/03/2010, 15h20
  4. Problème de compilation des fonctions pde
    Par pinoux dans le forum MATLAB
    Réponses: 1
    Dernier message: 31/03/2009, 18h33
  5. Compilation avec des fonctions virtuel pure
    Par vanitom dans le forum C++
    Réponses: 4
    Dernier message: 16/12/2005, 14h37

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo