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
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
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
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
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.
Partager