2017-05-23 1 views
0

je la table MySql suivante (seulement 845 lignes):MySql - Full balayage de table sur JOIN requête

CREATE TABLE `categories_nested_set` (
    `lft` int(11) NOT NULL DEFAULT '0', 
    `rgt` int(11) DEFAULT NULL, 
    `id` int(11) DEFAULT NULL, 
    `category` varchar(128) DEFAULT NULL, 
    PRIMARY KEY (`lft`), 
    UNIQUE KEY `id` (`id`), 
    UNIQUE KEY `rgt` (`rgt`), 
    KEY `idx_lftrgtid` (`id`,`lft`,`rgt`), 
    KEY `idx_lft` (`lft`), 
    KEY `i1` (`lft`) USING BTREE, 
    KEY `i2` (`rgt`) USING BTREE, 
    KEY `i3` (`id`) USING BTREE, 
    CONSTRAINT `fk_categories_nested_set_id_category` FOREIGN KEY (`id`) REFERENCES `categories` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

(vous pouvez voir que j'ai beaucoup d'indices là-bas, juste au cas où).

-je effectuer l'auto-jointure requête suivante:

SELECT * 
FROM categories_nested_set  AS H 
LEFT JOIN categories_nested_set AS I ON (H.lft > I.lft) 

qui génère les éléments suivants EXPLIQUEZ:

id,select_type,table,type,possible_keys,key,key_len,ref,rows,Extra 
1,SIMPLE,H,ALL,NULL,NULL,NULL,NULL,845,NULL 
1,SIMPLE,I,ALL,"PRIMARY,idx_lft,i1",NULL,NULL,NULL,845,"Range checked for each record (index map: 0x31)" 

enter image description here

Explain suggère que MySql est le choix de ne pas utiliser un index, et je ne peux pas comprendre pourquoi. La définition de la table montre que toutes les colonnes pertinentes sont indexées.

Dans le cadre d'une requête beaucoup plus grande (5 millions de lignes, 14 tables), cette pièce s'avère être un énorme goulot d'étranglement. Tout avis sera le bienvenu.

Merci,

+0

L'ensemble de données sur lequel vous avez exécuté 'EXPLAIN' n'a-t-il réellement que 845 lignes? MySQL n'utilisera pas nécessairement un index si, par exemple, l'ensemble de données est suffisamment petit. Vous devriez obtenir des statistiques de performance sur la requête plus large. –

+0

Oui, seulement 845 lignes. Différent expliquer sur la plus grande requête, évidemment beaucoup plus élaborée, mais néanmoins un balayage de table complet. – mils

+0

Eh bien, vous devez faire au moins un balayage complet de la table, pour la table sur le côté gauche de la jointure. –

Répondre

0

Je pense que vous devriez utiliser cette requête:

SELECT * FROM categories_nested_set AS H , categories_nested_set AS I where (H.lft > I.lft); 

L'idée est de ne pas utiliser JOIN parce qu'il oblige MySql à construire le résultat en faisant correspondre une ligne à la fois.

Dans la solution que je propose, la table inter-produits est construite sans jointure, ce qui permet à InnoDB de récupérer des lignes de la première table (H) indépendamment de l'autre table. L'index sur la deuxième table peut alors être utilisé par MySQL car aucun lien n'est fait depuis la table H.

Sur mon ordinateur, la solution proposée est environ 5 fois plus rapide, avec une table de 1000 enregistrements.

Voici le résultat de l'expliquer:

EXPLAIN SELECT * FROM categories_nested_set AS H , categories_nested_set AS I where (H.lft > I.lft); 

id select_type table type possible_keys key key_len ref rows Extra 
1 SIMPLE H ALL PRIMARY,idx_lft,i1 NULL NULL NULL 921 
1 SIMPLE I ALL PRIMARY,idx_lft,i1 NULL NULL NULL 921 Using where; Using join buffer 

Notez que vous pouvez également améliorer l'utilisation des index de votre demande en limitant les colonnes que vous extrayez (bien que ce soit pas toujours le cas).

+0

Cependant, juste par curiosité parce que cette requête génère beaucoup de combinaisons, qu'essayez-vous vraiment d'extraire de votre structure arborescente imbriquée avec cette requête? D'après ce que je comprends c'est toutes les paires de nœuds quand on est l'un après l'autre, mais je ne comprends pas ce que tu feras avec ça ... THanks –

+0

Salut Arnaud, je suis toujours en train de relire ta réponse, mais c'est ta question , la vraie requête est une requête de jeu imbriqué classique: 'LEFT JOIN categories_nested_set AS H SUR H.id = C.id_category LEFT JOIN categories_nested_set AS I ON (H.lft ENTRE I.lft ET I.rgt)' mais je voulais éliminer toute confusion quant à la performance de ENTRE – mils

+0

juste couru votre requête, même problème, voici le EXPLIQUER: 'id, select_type, table, type, possible_keys, clé, key_len, ref, lignes, supplémentaires 1, SIMPLE, H, TOUS, "PRIMAIRE, idx_lft, i1", NULL, NULL, NULL, 845, NULL 1, simple, je, tous, "PRIM ARY, idx_lft, i1 ", NULL, NULL, NULL, 845," Plage vérifiée pour chaque enregistrement (index map: 0x31) "' – mils