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) :
On repère deux conditions dont la résolution devrait être immédiate, les deux constante validant ces conditions.
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
55declare @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
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.
Et là ça va beaucoups plus vite, surtout si on a quelques indexes qui font mouche.
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
40SELECT 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
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.








Répondre avec citation










Partager