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

Développement SQL Server Discussion :

[2005] Astuce : rapidité query avec constante


Sujet :

Développement SQL Server

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éprouvé

    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    1 448
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juillet 2006
    Messages : 1 448
    Par défaut [2005] Astuce : rapidité query avec constante
    Bonjour,

    J'avais déjà remarqué (mais je viens de m'y reconfronter) que malheureusement Sql Server 2005 n'avait pas un comportement très intelligent vis à vis des conditions de jointure/filtre impliquant des constantes.

    Exemple (à lire en diagonale, sa complexité importe nullement) :
    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    declare @lastName varchar(200)
    declare @firstName varchar(200)
    declare @dateTime datetime
    declare @ClubId int
    declare @pageIndex int
    declare @pageSize int
    
    set @clubid = 1023
    set @lastName = null
    set @firstName = null
    set @dateTime = 0
    set @pageIndex = 1
    set @pageSize = 5
    
    
    SELECT
        Id
        , FederalNumber
        , Lname
        , Fname
        , Birthdate
        , HomeClub
        , ShortName
        , DENSE_RANK() OVER (ORDER BY LnameOK, FnameOK, BirthdateOK) AS GROUPID
        , ExpirationDate
    FROM (
        SELECT 
            M1.Id
            , M1.FederalNumber
            , M1.Lname
            , M1.Fname
            , M1.Birthdate
            , M1.HomeClub
            , M1.ShortName
            , M1.ExpirationDate
    
            , LnameOK
            , FnameOK
            , BirthdateOK
            , COUNT(*) OVER (PARTITION BY LnameOK, FnameOK, BirthdateOK) AS CNT_All
    		, SUM(CASE WHEN @ClubId IS NULL OR M1.HomeClub = @ClubId THEN 1 ELSE 0 END) OVER (PARTITION BY LnameOK, FnameOK, BirthdateOK) AS CNT_Club
        FROM dbo.VCentral_MemberDetails AS M1
        CROSS APPLY (
            SELECT
                CASE WHEN @lastName IS NULL THEN NULL ELSE M1.LName END AS LnameOK
                , CASE WHEN @firstName IS NULL THEN NULL ELSE M1.Fname END AS FnameOK
                , CASE WHEN @dateTime IS NULL THEN NULL ELSE M1.Birthdate END AS BirthdateOK
        ) AS Part
        WHERE (@lastName IS NULL OR M1.LName LIKE @lastName + '%')
        AND (@firstName IS NULL OR M1.Fname LIKE @firstName + '%')
        AND (@dateTime IS NULL OR @dateTime = 0 OR M1.Birthdate = @dateTime)
    ) EXT
    WHERE CNT_All > 1
    AND CNT_Club > 0
    On repère deux conditions dont la résolution devrait être immédiate, les deux constante validant ces conditions.
    Pourtant Sql Server va quand même faire des traitements pour vérifier la condition en entier ce qui peut s'avérer très lourd (des données supplémentaires à récupérer).

    J'ai trouvé (mais je ne prétendrai pas être le seul) un moyen à prioris très efficace pour parer à cela : rendre conditionnel la récupération même de ces données.
    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    SELECT
        Id
        , FederalNumber
        , Lname
        , Fname
        , Birthdate
        , HomeClub
        , ShortName
        , DENSE_RANK() OVER (ORDER BY LnameOK, FnameOK, BirthdateOK) AS GROUPID
        , ExpirationDate
    FROM (
        SELECT 
            M1.Id
            , M1.FederalNumber
            , M1.Lname
            , M1.Fname
            , M1.Birthdate
            , M1.HomeClub
            , M1.ShortName
            , M1.ExpirationDate
    
            , LnameOK
            , FnameOK
            , BirthdateOK
            , COUNT(*) OVER (PARTITION BY LnameOK, FnameOK, BirthdateOK) AS CNT_All
    		, SUM(CASE WHEN @ClubId IS NULL OR M1.HomeClub = @ClubId THEN 1 ELSE 0 END) OVER (PARTITION BY LnameOK, FnameOK, BirthdateOK) AS CNT_Club
        FROM dbo.VCentral_MemberDetails AS M1
        CROSS APPLY (
            SELECT
                CASE WHEN @lastName IS NULL THEN NULL ELSE M1.LName END AS LnameOK
                , CASE WHEN @firstName IS NULL THEN NULL ELSE M1.Fname END AS FnameOK
                , CASE WHEN @dateTime IS NULL THEN NULL ELSE M1.Birthdate END AS BirthdateOK
        ) AS Part
        WHERE (@lastName IS NULL OR (SELECT M1.LName WHERE @lastName IS NOT NULL) LIKE @lastName + '%')
        AND (@firstName IS NULL OR (SELECT M1.Fname WHERE @firstName IS NOT NULL) LIKE @firstName + '%')
        AND (@dateTime IS NULL OR @dateTime = 0 OR (SELECT M1.Birthdate WHERE @firstName IS NOT NULL) = @dateTime)
    ) EXT
    WHERE CNT_All > 1
    AND CNT_Club > 0
    Et là ça va beaucoups plus vite, surtout si on a quelques indexes qui font mouche.

    J'espère que ça pourra en aider certains, car je sais que bcp de dev se retrouve à devoir faire des queries dont les types de condition varient et qui doivent alors choisir entre un seul query avec plusieurs constantes (variables) ou un query dynamique.

  2. #2
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    22 010
    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 : 22 010
    Billets dans le blog
    6
    Par défaut
    As tu essayé le :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    M1.LName LIKE COALESCE(@lastName + '%', M1.LName)
    ???

    Parce que c'est le OR qui le gène !

    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/ * * * * *

  3. #3
    Modérateur

    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Janvier 2005
    Messages
    5 826
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2005
    Messages : 5 826
    Par défaut
    Bonjour,

    En apparté ce que demande SergeJack, je remarque ce que je pense être une erreur au sens SQL, et qui devient de plus en plus courante.
    Malheureusement le moteur de base de données les laisse passer
    L'opérateur CROSS APPLY est censé être utilisé avec des fonctions de table, et donc pas avec une requête.
    Une jointure de type CROSS JOIN me semble plus appropriée.
    Qu'en pensez-vous ?

    @++

  4. #4
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    22 010
    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 : 22 010
    Billets dans le blog
    6
    Par défaut
    Oh, je l'avais pas vu celle là.. Elle est catastrophique !

    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/ * * * * *

  5. #5
    Expert confirmé
    Avatar de mikedavem
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Août 2005
    Messages
    5 450
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Ain (Rhône Alpes)

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

    Informations forums :
    Inscription : Août 2005
    Messages : 5 450
    Par défaut
    Ah oui je viens de tester .. effectivement ça passe ...

  6. #6
    Membre éprouvé

    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    1 448
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juillet 2006
    Messages : 1 448
    Par défaut
    Citation Envoyé par SQLpro Voir le message
    As tu essayé le :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    M1.LName LIKE COALESCE(@lastName + '%', M1.LName)
    ???

    Parce que c'est le OR qui le gène !

    A +
    C'est tout aussi lent quz l'original et (@dateTime IS NULL OR @dateTime = 0 OR M1.Birthdate = @dateTime) n'est pas couvert.

    Par ailleurs, je fais un bon usage de CROSS APPLY, je ne sais pas où vous avez été cherchés que cette forme ne devrait pas être couverte (sous requête) mais pas dans la documentation de Sql Server en tout cas.

    left_table_source { CROSS | OUTER } APPLY right_table_source
    Specifies that the right_table_source of the APPLY operator is evaluated against every row of the left_table_source. This functionality is useful when the right_table_source contains a table-valued function that takes column values from the left_table_source as one of its arguments.

  7. #7
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    22 010
    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 : 22 010
    Billets dans le blog
    6
    Par défaut
    Citation Envoyé par Sergejack Voir le message
    C'est tout aussi lent quz l'original et (@dateTime IS NULL OR @dateTime = 0 OR M1.Birthdate = @dateTime) n'est pas couvert.

    Par ailleurs, je fais un bon usage de CROSS APPLY, je ne sais pas où vous avez été cherchés que cette forme ne devrait pas être couverte (sous requête) mais pas dans la documentation de Sql Server en tout cas.

    Tu as mal compris ce qui est dit dans la doc : Table Valued Fonction = Function qui renvoie une table et non pas sous requête.
    Le CROSS APPLY est extrêmement couteux autrement.

    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/ * * * * *

  8. #8
    Modérateur

    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Janvier 2005
    Messages
    5 826
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2005
    Messages : 5 826
    Par défaut
    Citation Envoyé par SergeJack
    Par ailleurs, je fais un bon usage de CROSS APPLY, je ne sais pas où vous avez été cherchés que cette forme ne devrait pas être couverte (sous requête)
    Dans ce cas pourquoi MS se serait amusé à ajouter un opérateur ?

    Citation Envoyé par SergeJack
    This functionality is useful when the right_table_source contains a table-valued function that takes column values from the left_table_source as one of its arguments.
    Et ça ne vous a pas mis la puce à l'oreille ?

    @++

  9. #9
    Expert confirmé
    Avatar de mikedavem
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Août 2005
    Messages
    5 450
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Ain (Rhône Alpes)

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

    Informations forums :
    Inscription : Août 2005
    Messages : 5 450
    Par défaut
    Ca éviterait ce genre d'absurdité .. fort coûteuse ... (Avec l'opérateur OUTER je précise) ... donc je ne parle pas du cas de SergeJack

    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    CREATE TABLE test
    (
     id INT IDENTITY PRIMARY KEY,
     col1 VARCHAR(10)
    )
    CREATE TABLE test2
    (
     id INT IDENTITY PRIMARY KEY,
     col1 VARCHAR(10)
    )
     
    DECLARE @i INT;
    SET @i = 0;
     
    WHILE @i < 100
    BEGIN 
     INSERT INTO test (col1) VALUES ('TEST_' + CAST(@i AS VARCHAR(5)));
     INSERT INTO test2 (col1) VALUES ('TEST_' + CAST(@i AS VARCHAR(5)));
     SET @i = @i + 1;
    END
     
    SET STATISTICS IO ON;
     
    SELECT 
    	test.id,
    	test.col1,
    	test2.col1 AS col2
    FROM test
    OUTER APPLY 
    (
     SELECT col1 
     FROM test2 
     WHERE test2.col1 = test.col1
    ) AS test2
    GO
     
    SELECT 
    	test.id,
    	test.col1,
    	test2.col1 AS col2
    FROM test
    LEFT JOIN test2
    ON test.id = test2.id;
     
    /*
    (100*ligne(s) affectée(s))
    Table 'test2'. Nombre d'analyses 1, lectures logiques 201, lectures physiques 0, lectures anticipées 0, lectures logiques de données d'objets volumineux 0, lectures physiques de données d'objets volumineux 0, lectures anticipées de données d'objets volumineux 0.
    Table 'test'. Nombre d'analyses 1, lectures logiques 2, lectures physiques 0, lectures anticipées 0, lectures logiques de données d'objets volumineux 0, lectures physiques de données d'objets volumineux 0, lectures anticipées de données d'objets volumineux 0. 
    */
     
    /*
    (100*ligne(s) affectée(s))
    Table 'test2'. Nombre d'analyses 1, lectures logiques 2, lectures physiques 0, lectures anticipées 0, lectures logiques de données d'objets volumineux 0, lectures physiques de données d'objets volumineux 0, lectures anticipées de données d'objets volumineux 0.
    Table 'test'. Nombre d'analyses 1, lectures logiques 2, lectures physiques 0, lectures anticipées 0, lectures logiques de données d'objets volumineux 0, lectures physiques de données d'objets volumineux 0, lectures anticipées de données d'objets volumineux 0.
    */
    ++

  10. #10
    Modérateur
    Avatar de Waldar
    Homme Profil pro
    Sr. Specialist Solutions Architect @Databricks
    Inscrit en
    Septembre 2008
    Messages
    8 454
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Sr. Specialist Solutions Architect @Databricks
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2008
    Messages : 8 454
    Par défaut
    Citation Envoyé par elsuket Voir le message
    Dans ce cas pourquoi MS se serait amusé à ajouter un opérateur ?
    Pour copier Oracle !

Discussions similaires

  1. SQL Server 2005 - ETL - Insertion données avec vérification.
    Par Mailgifson dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 23/12/2007, 12h22
  2. [SQL SERVER 2005] [DTS] connection à distance avec vba
    Par grandslam dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 01/06/2006, 12h00
  3. compiler avec constante dans un autre fichier
    Par hysah dans le forum C++
    Réponses: 8
    Dernier message: 28/03/2006, 22h57
  4. [ADO.Net][C#/SQL 2005] Comment faire INSERT avec variable ?
    Par hduchemin dans le forum Accès aux données
    Réponses: 1
    Dernier message: 25/01/2006, 17h34
  5. [Delphi 2005 Architect] Liaison DLL avec mon exe
    Par SkYsO dans le forum Langage
    Réponses: 20
    Dernier message: 20/10/2005, 08h33

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