Bonjour !

Je travaille sur la recherche de données dans une base via un formulaire web.
Pour récupérer le résultat je lance une requête puis je fais une boucle while avec un odbc_fetch_array.
Quand je teste cette recherche, tout fonctionne bien hormis le fait que la boucle prend un temps fou (enfin, je pense).
J'ai mis des traces dans mon code pour vérifier les temps de traitement, voici ce qu'il en résulte :
12/07/2011 16:19:27'000000 - debug [-avant requête]
12/07/2011 16:19:27'000000 - debug [--avant odbc_exec]
12/07/2011 16:19:34'000000 - debug [--après odbc_exec]
12/07/2011 16:19:34'000000 - debug [--avant odbc_fetch_array]
12/07/2011 16:19:49'000000 - debug [--après odbc_fetch_array]
12/07/2011 16:19:49'000000 - debug [-après requête]
Déjà, l’exécution de la requête prend un certain temps, mais je pense que c'est normal car c'est une très grosse requête avec différentes tables et la base de données contient plus de 50 000 lignes (je suis en test de charge). La voici :
Code sql : 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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
 
SELECT DISTINCT 
   Base_DocEnCours.IDBase_Image,
   Base_DocEnCours.NbreNotes,
   Base_DocEnCours.IndexPrincipal,
   Base_DocEnCours.CodeDocumentAccepte,
   Base_DocEnCours.DocumentArchive,
   Base_DocEnCours.DateHeureFinCirculation,
   Index_Facture.CodeFournisseur,
   Index_Facture.NomFournisseur,
   Index_Facture.NumeroFacture,
   Index_Facture.DateFacture,
   Index_Facture.Echeance,
   Index_Facture.MontantHT,
   Index_Facture.MontantTVA,
   Index_Facture.MontantTTC,
   Index_Facture.Devise,
   Index_Facture.NumeroCommande,
   Index_Facture.NumeroVirement,
   Index_Facture.CompteCharge,
   Index_Facture.LibelleCompteCharge,
   Index_Facture.DateFactureBAP,
   Index_Facture.DatePaiement,
   TypeDocument.TypeDocument,
   Base_Sociétés.NomSociété,
   Base_Dossier.NomDossier,
   Base_ValeurZoneUtilisateur.ValeurZone1,
   Base_ValeurZoneUtilisateur.ValeurZone2,
   Base_ValeurZoneUtilisateur.ValeurZone3
 FROM 
   Base_DocEnCours LEFT OUTER JOIN Base_Circulation_Facture ON Base_DocEnCours.IDBase_Image = Base_Circulation_Facture.IDBase_Image,
   TypeDocument INNER JOIN Base_DocEnCours ON TypeDocument.CodeTypeDoc = Base_DocEnCours.CodeTypeDoc, 
   Base_Sociétés INNER JOIN Base_DocEnCours ON Base_Sociétés.CodeSociété = Base_DocEnCours.CodeSociété, 
   Base_DocEnCours LEFT OUTER JOIN Base_Dossier ON Base_DocEnCours.CodeDossier = Base_Dossier.CodeDossier,
   Base_DocEnCours LEFT OUTER JOIN Base_ValeurZoneUtilisateur ON Base_DocEnCours.IDBase_Image = Base_ValeurZoneUtilisateur.IDBase_Image, 
   Base_DocEnCours LEFT OUTER JOIN Index_Facture ON Base_DocEnCours.IDBase_Image = Index_Facture.IDBase_Image
 WHERE 
   Base_DocEnCours.DocumentSupprime=0
   AND Base_DocEnCours.OrdreDoc = 1
   AND ImagePresente = 1
   AND (
	 Base_DocEnCours.IDBase_Image IN ( 
	   SELECT DISTINCT
		 Base_Circulation_Facture.IDBase_Image
	   FROM
		 Base_Circulation_Facture
	   WHERE
		 Base_Circulation_Facture.Nom = 'ADMIN'
	 )
	 OR
	 Base_DocEnCours.IDBase_Image IN (
	   SELECT DISTINCT 
		 Base_DocEnCours.IDBase_Image
	   FROM 
		 Base_DocEnCours,
		 Base_GroupeDroit_Sociétés,
		 Base_Utilisateurs_web
	   WHERE 
		 Base_DocEnCours.CodeSociété = Base_GroupeDroit_Sociétés.CodeSociété
		 AND Base_DocEnCours.CodeTypeDoc = Base_GroupeDroit_Sociétés.CodeTypeDoc
		 AND Base_GroupeDroit_Sociétés.ConsulteTousDocuments = 1
		 AND Base_GroupeDroit_Sociétés.NomGroupe = Base_Utilisateurs_web.NomGroupe
		 AND Base_Utilisateurs_web.Nom = 'ADMIN'
	 )
   )
 
 
 
   AND IndexPrincipal LIKE '0000002%'
 
  UNION 
 
SELECT DISTINCT 
   Base_DocArchive.IDBase_Image,
   Base_DocArchive.NbreNotes,
   Base_DocArchive.IndexPrincipal,
   Base_DocArchive.CodeDocumentAccepte,
   Base_DocArchive.DocumentArchive,
   Base_DocArchive.DateHeureFinCirculation,
   Index_Facture.CodeFournisseur,
   Index_Facture.NomFournisseur,
   Index_Facture.NumeroFacture,
   Index_Facture.DateFacture,
   Index_Facture.Echeance,
   Index_Facture.MontantHT,
   Index_Facture.MontantTVA,
   Index_Facture.MontantTTC,
   Index_Facture.Devise,
   Index_Facture.NumeroCommande,
   Index_Facture.NumeroVirement,
   Index_Facture.CompteCharge,
   Index_Facture.LibelleCompteCharge,
   Index_Facture.DateFactureBAP, 
   Index_Facture.DatePaiement,
   TypeDocument.TypeDocument,
   Base_Sociétés.NomSociété,
   Base_Dossier.NomDossier,
   Base_ValeurZoneUtilisateur.ValeurZone1,
   Base_ValeurZoneUtilisateur.ValeurZone2,
   Base_ValeurZoneUtilisateur.ValeurZone3
 FROM 
   Base_DocArchive LEFT OUTER JOIN Base_Circulation_Facture ON Base_DocArchive.IDBase_Image = Base_Circulation_Facture.IDBase_Image,
   TypeDocument INNER JOIN Base_DocArchive ON TypeDocument.CodeTypeDoc = Base_DocArchive.CodeTypeDoc, 
   Base_Sociétés INNER JOIN Base_DocArchive ON Base_Sociétés.CodeSociété = Base_DocArchive.CodeSociété, 
   Base_DocArchive LEFT OUTER JOIN Base_Dossier ON Base_DocArchive.CodeDossier = Base_Dossier.CodeDossier,
   Base_DocArchive LEFT OUTER JOIN Base_ValeurZoneUtilisateur ON Base_DocArchive.IDBase_Image = Base_ValeurZoneUtilisateur.IDBase_Image, 
   Base_DocArchive LEFT OUTER JOIN Index_Facture ON Base_DocArchive.IDBase_Image = Index_Facture.IDBase_Image
 WHERE
   Base_DocArchive.DocumentSupprime=0
   AND Base_DocArchive.OrdreDoc = 1
   AND ImagePresente = 1
   AND (
	 Base_DocArchive.IDBase_Image IN ( 
	   SELECT DISTINCT
		 Base_Circulation_Facture.IDBase_Image
	   FROM
		 Base_Circulation_Facture
	   WHERE
		 Base_Circulation_Facture.Nom = 'ADMIN'
	 )
	 OR
	 Base_DocArchive.IDBase_Image IN (
	   SELECT DISTINCT 
		 Base_DocArchive.IDBase_Image
	   FROM 
		 Base_DocArchive,
		 Base_GroupeDroit_Sociétés,
		 Base_Utilisateurs_web
	   WHERE 
		 Base_DocArchive.CodeSociété = Base_GroupeDroit_Sociétés.CodeSociété
		 AND Base_DocArchive.CodeTypeDoc = Base_GroupeDroit_Sociétés.CodeTypeDoc
		 AND Base_GroupeDroit_Sociétés.ConsulteTousDocuments = 1
		 AND Base_GroupeDroit_Sociétés.NomGroupe = Base_Utilisateurs_web.NomGroupe
		 AND Base_Utilisateurs_web.Nom = 'ADMIN'
	 )
   )
 
   AND IndexPrincipal LIKE '0000002%'
 
  ORDER BY IndexPrincipal ASC


Ensuite, la boucle sur fetch array prends environ 15 secondes, sachant que la requête renvoi 1000 enregistrements (il boucle donc 1000 fois).

Voici le code php que j'utilise pour récupérer les enregistrements dans un tableau.
Code php : 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
 
//On lance la requête
debug("--avant odbc_exec",false,true);
$rs_Requete = odbc_exec(self::$Connexion,$p_Requete);
debug("--après odbc_exec",false,true);
 
//On récupère les résultats dans un tableau
$v_NbEnr = 0;
debug("--avant odbc_fetch_array",false,true);
while($v_Data = odbc_fetch_array($rs_Requete))
{
	//On enregistre la ligne dans le tableau
	$t_Data[$v_NbEnr] = $v_Data;
	//On compte le nombre de ligne
	$v_NbEnr++;
}
debug("--après odbc_fetch_array",false,true);
(Je l'ai simplifié car je fais d'autres tests en dehors du while mais qui ne sont pas important ici à priori.)



Ensuite, le tableau est transformé en collection d'objet dans une autre méthode et je lance l'affichage dans une autre page, ces opérations ne prennent pas de temps d'après mes tests.

Voilà, j'ai donc plus de 20 secondes à attendre lorsque je clique sur le bouton rechercher dans ma page.

J'ai déjà réduit la requête pour retirer certains champs inutiles dans le select (contrairement à un select * par exemple) et simplifier au maximum les jointures (je pense) pour passer par le moins de table possible selon mon MCD.

Est-ce que vous avez une idée pour optimiser la vitesse d'affichage ?

J'ai pensé passer par de l'Ajax pour afficher les réponses ligne par ligne, ainsi le client n'aurait pas à attendre 20 secondes pour commencer à voir des résultats. Mais n'ayant jamais utiliser Ajax, je ne sais pas trop comment m'y prendre pour afficher ligne par ligne ; et je ne sais pas non plus si c'est pertinent : il faudrait relancer la requête pour chaque ligne, non ?

Sinon peut-être y-a-t-il une autre solution ou une optimisation de code à faire ? utiliser une autre instruction à la place de odbc_fetch_array ? optimiser encore plus la requête ? je ne sais pas...


Pour info, ma base de données est HyperFileSql (de PCSoft) car elle est utilisée actuellement pour une application en client lourd, mon boulot c'est de refaire cette appli en web ^^