2017-10-06 3 views
0

Ici, je vais ajouter une partie de ma question, car il est des informations sensibles et j'utiliser des noms pas réel:MySQL ignorer l'index même avec l'index d'indice d'utilisation ou de force

SELECT 
    `entity`.`id`, 
    `entity`.`requirements`, 
    `entity`.`description`, 
    `entity`.`status`, 
    `entity_videos`.`length`, 
    `entity_videos`.`quality`, 
    `states`.`name`, 
    `uploads`.`id`, 
    `uploads`.`name` 
    FROM `entity` 
    LEFT JOIN `states` ON `states`.`id` = `entity`.`state_id` 
    INNER JOIN `uploads` FORCE INDEX (`uploadable_id_index`) 
     ON `uploads`.`uploadable_type` = 'Entity' 
     AND `uploads`.`category` = 'Icon' 
     AND (`uploads`.`uploadable_id` = `entity`.`id` 
       OR `uploads`.`uploadable_id` = `entity`.`parent_entity_for_icon` 
      ) 
    INNER JOIN `entity_videos` FORCE INDEX (entity_videos_entity_id_index) 
     ON `entity_videos`.`entity_id` = `entity`.`id` 
    WHERE `entity`.`status` = 'active' 

Le problème est que optimiseur Mysql ne veulent pas pour utiliser l'index uploadable_id_index. Une partie de l'expliquer:

part of explain querye

Comme je sais FORCE INDEX est optimiseur de force à utiliser indice sauf situation optimiseur ne peut pas utiliser l'index. Que dois-je faire pour forcer cet index et ne pas effectuer une analyse complète de la table? J'ai essayé d'enlever entity_videos_entity_id_index aussi j'ai essayé d'ajouter uploads l'information de table à la clause where, mais rien ne fonctionne pour moi. Des idées? Merci beaucoup pour toute aide

Mise à jour:

Avec l'aide de @Barmar et @PaulSpiegel je trouve cette question est en (uploads.uploadable_id = entity.id OR uploads.uploadable_id = entity.parent_entity_for_icon). Et jouer avec requête pendant un certain temps, je trouve que la meilleure solution dans mon cas est:

SELECT 
    `entity`.`id`, 
    `entity`.`requirements`, 
    `entity`.`description`, 
    `entity`.`status`, 
    `entity_videos`.`length`, 
    `entity_videos`.`quality`, 
    `states`.`name`, 
    `icon`.`id`, 
    `icon`.`name`, 
    `parent_offer_icon`.`id`, 
    `parent_offer_icon`.`name` 
    FROM `entity` 
    LEFT JOIN `states` ON `states`.`id` = `entity`.`state_id` 
    LEFT JOIN `uploads` as `icon` FORCE INDEX (`uploadable_id_index`) 
     ON `icon`.`uploadable_type` = 'Entity' 
     AND `icon`.`category` = 'Icon' 
     AND `icon`.`uploadable_id` = `entity`.`id` 
    LEFT JOIN `uploads` as `parent_offer_icon` FORCE INDEX (`uploadable_id_index`) 
     ON `parent_offer_icon`.`uploadable_type` = 'Entity' 
     AND `parent_offer_icon`.`category` = 'Icon' 
     AND `parent_offer_icon`.`uploadable_id` = `entity`.`parent_entity_for_icon` 
    INNER JOIN `entity_videos` FORCE INDEX (entity_videos_entity_id_index) 
     ON `entity_videos`.`entity_id` = `entity`.`id` 
    WHERE `entity`.`status` = 'active' 
     AND (parent_offer_icon.id IS NOT NULL 
       OR icon.id IS NOT NULL) 

Je suis toujours ouvert à d'autres suggestions :)

+1

La condition 'de OR' pourrait être le problème. Essayez d'utiliser 'uploadable_id IN (entity.id, entity.parent_entity_for_icon)' – Barmar

+0

@Barmar merci pour une proposition mais cela ne fonctionne pas non plus. Et j'ai oublié, il y a quelques jours quand il y avait beaucoup moins d'enregistrements dans DB optimizer sélectionner cet index, peut-être qu'il est vraiment beaucoup plus rapide de faire un scan complet au lieu d'utiliser un index? –

+0

Habituellement, les index sont plus utiles lorsque la table devient plus grande. Mais peut-être que la cardinalité de cet index est trop faible. Utilisez 'SHOW INDEX FROM uploads 'pour voir. – Barmar

Répondre

1

Commençons en tournant le satanés OR en UNION:

(SELECT e.id AS eid, 
      u.id AS uid, 
      u.name AS uname 
    FROM `uploads` AS u 
    INNER JOIN `entity` AS e 
     ON u.`uploadable_id` = e.`id` 
    WHERE u.`uploadable_type` = 'Entity' 
     AND u.`category` = 'Icon' 
     AND e.status = 'active' 
) UNION DISTINCT 
(SELECT e.id AS eid, 
      u.id AS uid, 
      u.name AS uname 
    FROM `uploads` AS u 
    INNER JOIN `entity` AS e 
     ON u.`uploadable_id` = e.`parent_entity_for_icon` 
    WHERE u.`uploadable_type` = 'Entity' 
     AND u.`category` = 'Icon' 
     AND e.status = 'active' 
) 

qui aura besoin certains de ces indices:

uploads: INDEX(uploadable_type, category, uploadable_id, id, name) 
entity: INDEX(parent_entity_for_icon, status, id) 

(Je suppose que entity a PRIMARY KEY(id)? S'il vous plaît fournir SHOW CREATE TABLE donc je n'ai pas à deviner.) S'il y a des problèmes avec un index si long, faites le moi savoir; Je peux probablement fournir une solution de contournement.

En transformant le OR en UNION, différents index peuvent être utilisés pour chaque pièce. Avec OR, l'optimiseur pique habituellement et fait quelque chose d'inefficace.

Veuillez vérifier que la requête ci-dessus s'exécute rapidement et produit une sortie raisonnable. Alors ...

SELECT e.`id`, e.`requirements`, e.`description`, e.`status`, 
     ev.`length`, ev.`quality`, 
     s.`name`, 
     uid, uname 
    FROM (the-query-above) AS i 
    JOIN `entity` AS e ON e.id = i.eid 
    LEFT JOIN `states` AS s ON s.`id` = e.`state_id` 
    INNER JOIN `entity_videos` AS ev ON ev.`entity_id` = i.eid 

Autre que PRIMARY KEY(id) sur chaque table, vous aurez besoin

entity_videos: INDEX(entity_id) -- good, or 
entity_videos: INDEX(entity_id, length, quality) -- better ("covering") 

Ne pas utiliser FORCE INDEX.

Plus d'informations sur la création d'index: http://mysql.rjweb.org/doc.php/index_cookbook_mysql

+0

Merci pour la proposition, je crois que c'est peut être le meilleur, mais dans mon cas, il faut un peu de temps pour exécuter la requête avec votre solution et moi, mais votre solution est plus difficile à mettre en œuvre en utilisant ORM. J'ai vu ton profil et on dirait que tu es un expert en MySQL :). Peut-être serez-vous intéressé (e) de voir la structure complète des requêtes et des tables et nous pourrons continuer une conversation en privé (peut-être par e-mail)? En tout cas, merci !!! –

+0

Oui, les ORM ont tendance à nuire à la performance. mysql à rjweb dot org. Pouvez-vous commencer par chronométrer le 'UNION' et l'équivalent' OR' _with_ les index suggérés. –