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

Requêtes MySQL Discussion :

Optimisation count et join


Sujet :

Requêtes MySQL

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Homme Profil pro
    développeur
    Inscrit en
    Octobre 2004
    Messages
    481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : développeur
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Octobre 2004
    Messages : 481
    Par défaut Optimisation count et join
    Bonjour,

    J'ai cette requête :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    SELECT COUNT(*) AS NB, ID_LOTERIE
    FROM BILLET
      JOIN PARTICIPE ON PARTICIPE.ID_BILLET = BILLET.ID_BILLET
    WHERE PARTICIPE.ID_LOTERIE = 29
          AND VALIDITE_BILLET = 1;
    Elle prend en moyenne 500 ms.

    J'ai ajouté un index sur VALIDITE_BILLET, on descend à 310-320ms.
    Mais je trouve que c'est encore long.

    Si je fais seulement
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    SELECT ID_LOTERIE
    FROM BILLET
      JOIN PARTICIPE ON PARTICIPE.ID_BILLET = BILLET.ID_BILLET
    WHERE PARTICIPE.ID_LOTERIE = 29
          AND VALIDITE_BILLET = 1;
    J'arrive à 35ms.

    Voici l'explain :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    id 	select_type 	table 		partitions 	type 	possible_keys 				key 		key_len 	ref 			rows 	filtered 	Extra 	
    1 	SIMPLE 		PARTICIPE 	NULL 		ref 	PRIMARY,FK_PARTICIPE3,index_loterie 	PRIMARY 	4 		const 			93715 	100.00 		Using index
    1 	SIMPLE 		BILLET 		NULL 		eq_ref 	PRIMARY,index_validite 			PRIMARY 	4 		PARTICIPE.ID_BILLET 	1 	99.04 		Using where
    Index sur la table billet
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Nom index		Type	Unique		Compressé	Colonne			Cardinalité	Interclassement		Null
    PRIMARY			BTREE	Oui		Non		ID_BILLET		359948		A			Non	
    FK_VALIDE		BTREE	Non		Non		ID_JOUEUR		1739		A			Oui	
    index_validite		BTREE	Non		Non		VALIDITE_BILLET		2		A			Non
    index de la table participe
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    Nom index	Type	Unique		Compressé	Colonne			Cardinalité	Interclassement		Null
    PRIMARY		BTREE	Oui		Non		ID_LOTERIE					A		Non	
    							ID_PARIEUR					A		Non
    							ID_BILLET		359948			A		Non
    FK_PARTICIPE2	BTREE	Non		Non		ID_PARIEUR		609			A		Non	
    FK_PARTICIPE3	BTREE	Non		Non		ID_BILLET		359948			A		Non	
    index_loterie	BTREE	Non		Non		ID_LOTERIE		13			A		Non
    Une idée pour diminuer encore le temps de traitement avec COUNT ?

  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 001
    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 001
    Billets dans le blog
    6
    Par défaut
    Aucun de ces index ne sert votre requête !
    Vous avez des index monocolonne alors que votre requête utilise 2 colonne pour BILLET et 2 autres pour PARTICIPE

    Créez les bons index,et vous verrez que cela marchera mieux....
    par exemple :
    • PARTICIPE => (ID_LOTERIE, ID_BILLET);
    • BILLET => (VALIDITE_BILLET, ID_BILLET);


    Apprenez à créer les bons index à l'aide de mon cours :
    https://sqlpro.developpez.com/cours/quoi-indexer
    https://blog.developpez.com/sqlpro/p..._oui_mais_quoi
    https://blog.developpez.com/sqlpro/p...ut_sur_l_index
    https://blog.developpez.com/sqlpro/p...sql_sargable_c

    A +



    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
    Membre éclairé
    Homme Profil pro
    développeur
    Inscrit en
    Octobre 2004
    Messages
    481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : développeur
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Octobre 2004
    Messages : 481
    Par défaut
    J'ai bien compris l'intérêt de mettre des index sur plusieurs colonnes à la fois, avec l'importance de l'ordre des colonnes.

    J'ai fait l'exercice d'ajouter les index progressivement, avec cette requête :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    SELECT COUNT(*) AS NB, ID_LOTERIE
    FROM BILLET
      JOIN PARTICIPE ON PARTICIPE.ID_BILLET = BILLET.ID_BILLET
    WHERE PARTICIPE.ID_LOTERIE = 29
          AND VALIDITE_BILLET = 1;
    Je mets le résultat de l'explication de la requête.
    Le temps indiqué est celui du traitement global que je fais, incluant la requête.

    Sans index - 2,8 secondes

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    id 	select_type 	table 		partitions 	type 	possible_keys 		key 		key_len 	ref 			rows 	filtered 	Extra 	
    1 	SIMPLE 		BILLET 		NULL 		ALL 	PRIMARY 		NULL 		NULL 		NULL 			361131 	10.00 		Using where
    1 	SIMPLE 		PARTICIPE 	NULL 		ref 	PRIMARY,FK_PARTICIPE3 	FK_PARTICIPE3 	8 		BILLET.ID_BILLET,const 	1 	100.00 		Using index
    index table billet : validite - 1.1 secondes

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    id 	select_type 	table 		partitions 	type 	possible_keys 			key 		key_len 	ref 			rows 	filtered 	Extra 	
    1 	SIMPLE 		PARTICIPE 	NULL 		ref 	PRIMARY,FK_PARTICIPE3 		PRIMARY 	4 		const 			179778 	100.00 		Using index
    1 	SIMPLE 		BILLET 		NULL 		eq_ref 	PRIMARY,billet_validite 	PRIMARY 	4 		PARTICIPE.ID_BILLET 	1 	99.04 		Using where
    index table billet : validite/id_billet - 1 seconde
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    id 	select_type 	table 	 	partitions 	type 	possible_keys 	 	 	key 	 	key_len 	ref 	 	 	rows 	filtered 	Extra 	
    1 	SIMPLE 	 	PARTICIPE 	NULL 	 	ref 	PRIMARY,FK_PARTICIPE3 	 	PRIMARY 	4 	 	const 	 	 	179778 	100.00 	 	Using index
    1 	SIMPLE 	 	BILLET 	 	NULL 	 	eq_ref 	PRIMARY,billet_validite 	PRIMARY 	4 	 	PARTICIPE.ID_BILLET 	1 	99.45 	 	Using where
    index table billet : validite/id_billet - index table participe : id_loterie - 1,1 secondes
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    id 	select_type 	table 	 	partitions 	type 	possible_keys 	 	 	 	key 	 	key_len 	ref 	 	 	rows 	filtered 	Extra 	
    1 	SIMPLE 	 	PARTICIPE 	NULL 	 	ref 	PRIMARY,FK_PARTICIPE3,ID_LOTERIE 	ID_LOTERIE 	4 	 	const 	 	 	179778 	100.00 	 	Using index
    1  	SIMPLE 	 	BILLET 	 	NULL 	 	eq_ref 	PRIMARY,billet_validite 	 	PRIMARY 	4 	 	PARTICIPE.ID_BILLET 	1 	99.45 	 	Using where
    index table billet : validite/id_billet - index table participe : id_loterie/id_billet - 1,1 secondes
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    id 	select_type 	table 		partitions 	type 	possible_keys 					key 			key_len 	ref 			rows 	filtered 	Extra 	
    1 	SIMPLE 		PARTICIPE 	NULL 		ref 	PRIMARY,FK_PARTICIPE3,ID_LOTERIE_ID_BILLET 	ID_LOTERIE_ID_BILLET 	4 		const 			179778 	100.00 		Using index
    1 	SIMPLE 		BILLET 		NULL 		eq_ref 	PRIMARY,billet_validite 			PRIMARY 		4 		PARTICIPE.ID_BILLET 	1 	99.45 		Using where
    index table billet : validite/id_billet et supression de l'index primary - index table participe : id_loterie/id_billet - 0,5 secondes
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    id 	select_type 	table 		partitions 	type 	possible_keys 					key 			key_len 	ref 			 	rows 	filtered 	Extra 	
    1 	SIMPLE 		PARTICIPE 	NULL 		ref 	PRIMARY,FK_PARTICIPE3,ID_LOTERIE_ID_BILLET 	ID_LOTERIE_ID_BILLET 	4 	 	const 	 	  		179778 	100.00 	 	Using index
    1 	SIMPLE 		BILLET 		NULL 		eq_ref 	VALIDITE_BILLET 	 	 	 	VALIDITE_BILLET  	5 	 	const, PARTICIPE.ID_BILLET 	 1 	100.00 	 	Using index
    On voit que la mise en place de l'index billet_validite sur la colonne VALIDITE seule permet un gain x2 environ. Ca correspond à l'aspect "sargable" si j'ai bien compris.
    La suppression de l'index primary sur la table billet permet à nouveau un gain x2, en "forçant" l'utilisation de l'index billet_validite sur les colonnes validite/id_billet.
    En remettant l'index PRIMARY sur la table billet avec les colonnes id_billet/validite et en conservant l'index billet_validite, on gagne quelques millisecondes encore.

    L'ajout des autres index sur la table participe ne changent rien.

  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 001
    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 001
    Billets dans le blog
    6
    Par défaut
    Ceci dit, MySQL n'est absolument pas un SGBD fait pour les grosses volumétries.... En pratique à partir de quelques dizaines de Go et quelques millions de lignes il est totalement dépassé par rapport à SQL Server, Oracle ou DB2...
    Si vous voulez du libre, PostGreSQL restent un bon choix pour des volumétries moyennes...

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

Discussions similaires

  1. [MySQL] Multiplier/additionner des COUNT en JOIN LEFT?
    Par kfa1983 dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 29/03/2011, 16h35
  2. Multiple count et join
    Par levalp dans le forum Requêtes
    Réponses: 11
    Dernier message: 22/06/2010, 15h48
  3. count et join de deux tables
    Par crazyvirus dans le forum Requêtes
    Réponses: 1
    Dernier message: 12/03/2010, 05h52
  4. optimisation count(*) vs count(champs)
    Par oadin dans le forum MS SQL Server
    Réponses: 4
    Dernier message: 21/03/2008, 10h04
  5. multiples COUNT et JOIN
    Par Ryle dans le forum Langage SQL
    Réponses: 2
    Dernier message: 30/08/2004, 08h26

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