requête sql complète ou traitement php?

d0m
Mammouth du PHP | 1141 Messages

14 déc. 2007, 11:34

Bonjour,

petite question sql/php :

j'ai une requete à faire et extraire sur une valeur le top 10 des valeurs maximales et le top 10 des moyennes.

Que vaut il mieux faire :
- directement les calculs dans la requête SQL
- faire un SELECT de tout et faire le tri pour les top en php?

ViPHP
ViPHP | 2287 Messages

14 déc. 2007, 11:38

Bonjour,

Sans hésitation : dans la requête SQL 8-) C'est à la fois plus simple, plus rapide et plus propre.
if(!@work()){ Nespresso(); } else { what(); }
______________________________

d0m
Mammouth du PHP | 1141 Messages

14 déc. 2007, 12:02

sachant qu'en une seule requête j'ai à faire 2 tops 10 :
- celui des max
- celui des moyennes

est ce possible?

Parce que je travaille sur une base oracle et le temps d'execution de la requête est assez élevé par rapport à un traitement php.

En gros 2 requêtes pour les 2 tops 10 me prendrait + de temps qu'une requête + 2 traitements.

ViPHP
ViPHP | 2287 Messages

14 déc. 2007, 13:09

J'aurais tendance à croire que si php arrive à être plus rapide qu'oracle, c'est que le traitement que chacun doit faire n'est pas exactement le même, ou alors qu'il y a de grosses améliorations possibles sur les tables ou sur les requêtes jouées.

Mais difficile de t'en dire plus sans savoir exactement de quoi on parle (schéma de tables, requetes, code, etc) :roll:
if(!@work()){ Nespresso(); } else { what(); }
______________________________

ViPHP
ViPHP | 4039 Messages

14 déc. 2007, 14:26

ça dépend aussi de l'interfacage utilise pour te connecter oracle..
Mais qu'importe. (je suis ici - dernier petit projet)
Berze going social.

d0m
Mammouth du PHP | 1141 Messages

14 déc. 2007, 15:24

un peu plus de précision :
j'utilise les fonction OCI de la librairie php pour me connecter à Oracle.
Il se trouve que c'est réel, il faut du temps (5s) pour que la requête soit effectuée. Je ne sais pas d'où ça vient mais je n'ai pas beaucoup de droits sur la base, je dois m'en contenter.

j'ai une simple table contenant les champs suivant :

Code : Tout sélectionner

create table matable( id integer, nom varchar, dateheuredebut date, dateheurefin date);
A savoir que pour un même nom il peut y avoir plusieurs enregistrement différents avec donc des id différents.

J'essaie d'avoir la durée maximale par nom et la durée moyenne.

J'ai donc cette requête pour la durée maximale de chaque nom:

Code : Tout sélectionner

SELECT nom, SUBSTR ((TO_CHAR (MAX(dateheurefin - dateheuredebut), 'HH24:MI:SS')), 12, 8 ) dureemax, FROM matable GROUP BY nom ORDER BY dureemax DESC
Par contre il me faut également la durée moyenne, et là après quelques tentatives, je ne vois pas comment l'intégrer à la requête en SQL. Une deuxième requête doublerait le temps d'execution donc ce n'est pas envisageable.

Voivi au cas où mon code pour effectuer la requête :
function topx_max($nb,$debut,$fin){
	$resultat = array();

	$connexion = @ocilogon(***,***,***);
	if($connexion == false){
		$msg = ocierror();
		print_r($msg);
		$erreur = $msg['code'];
	}
	else{
		$requete = 
			"SELECT nom,
             SUBSTR ((TO_CHAR (MAX(dateheurefin - dateheuredebut), 'HH24:MI:SS')), 12, 8 ) dureemax,
             FROM matable
             GROUP BY nom
             ORDER BY dureemax DESC";	
		//echo $requete.'<BR><BR>';
		
		$gestionnaire_requete = ociparse($connexion,$requete);
		if (!$gestionnaire_requete) {
			$e = OCIError($connexion).'<BR>';
			print htmlentities($e);
			$tablespaces = false;
		}
		else{
			$r = ociexecute($gestionnaire_requete,OCI_DEFAULT);
			if (!$r) {
				$e = OCIError($gestionnaire_requete).'<BR>';
				echo htmlentities($e);
				$tablespaces = false;
			}
			else{
				while (OCIFetchInto($gestionnaire_requete, $ligne, OCI_ASSOC) ) {
					//print_r($ligne);echo '<BR>';
					//$resultat[$ligne['NOM']] = $ligne;
				}
			}
		}
		OCILogoff($connexion);
	}
	
	
	return $resutat;
}

ViPHP
ViPHP | 5924 Messages

15 déc. 2007, 00:04

Deux questions :
Tu as combien d'enregistrements dans ta table (ordre de grandeur) ?
Tu n'as pas de clés sur ta table ?

ViPHP
AB
ViPHP | 5818 Messages

15 déc. 2007, 05:14

Quand il y a un doute pourquoi ne pas essayer les deux solutions et un petit bench pour départager ?

Mammouth du PHP | 881 Messages

15 déc. 2007, 06:54

Tu n'as pas de clés sur ta table ?
Avec SQL, les index multiplient la rapidité. Crée un index et déjà ton premier classement (valeurs max) sera fait avant même d'écrire la requête.
Soyez artisans de paix

Administrateur PHPfrance
Administrateur PHPfrance | 3088 Messages

15 déc. 2007, 08:08

Il n'y a pas de clause WHERE, donc un index ne devrait pas influer sur les performances. Une vraie bonne idée serait de stocker la valeur de (dateheurefin - dateheuredebut) en secondes dans une colonne "duree". Ensuite tu n'aurais plus qu'à faire un

Code : Tout sélectionner

SELECT MAX(duree), AVG(duree) ...
Je ne vois pas comment obtenir deux "top n" à partir de la même requête, donc tu risques de devoir faire deux requêtes quasi-identiques. Pour de meilleures performances tu peux regarder du côté d'une procédure stockée qui lirait un curseur sur

Code : Tout sélectionner

SELECT nom, MAX(duree) AS max_duree, AVG(duree) AS avg_duree FROM matable GROUP BY nom
...et qui s'occuperait de ne garder que les n plus grandes valeurs de max_duree et avg_duree de chaque "nom". Si tu veux un classement global, alors ton GROUP BY nom n'a pas lieu d'être.

Suivant la fréquence d'utilisation de cette requête, tu pourrais créer une vue matérialisée pour accélérer le traitement, mais cette théorie reste à vérifier.

PS: je ne connais rien à Oracle.

d0m
Mammouth du PHP | 1141 Messages

17 déc. 2007, 10:16

Tu n'as pas de clés sur ta table ?
si désolé, un oubli. La clé est le champ id.
Crée un index et déjà ton premier classement (valeurs max) sera fait avant même d'écrire la requête.
Je n'ai accès qu'en lecture à la base, pas de modif, pas d'ajout rien. Comme je le disais je dois me débrouiller avec ce que j'ai.

Sans une requête unique capable de faire le travail j'ai opté pour un traitement php qui pour une fois se fait plus rapidement qu'une requête sous oracle.