web-dev-qa-db-fra.com

MySQL n'utilise pas d'index avec la clause WHERE IN?

J'essaie d'optimiser certaines des requêtes de base de données dans mon application Rails et j'en ai plusieurs qui me stoppent. Ils utilisent tous une clause IN dans la clause WHERE et effectuent tous des analyses de table complètes, même si un index approprié semble être en place.

Par exemple:

SELECT `user_metrics`.* FROM `user_metrics` WHERE (`user_metrics`.user_id IN (N,N,N,N,N,N,N,N,N,N,N,N))

effectue une analyse complète de la table et EXPLAIN dit:

select_type: simple
type: all
extra: using where
possible_keys: index_user_metrics_on_user_id  (which is an index on the user_id column)
key: (none)
key_length: (none)
ref: (none)
rows: 208

Les index ne sont-ils pas utilisés lorsqu'une instruction IN est utilisée ou dois-je faire quelque chose différemment? Les requêtes ici sont générées par Rails afin que je puisse revoir la définition de mes relations, mais je pensais commencer par des corrections potentielles au niveau de la base de données.

48
jasonlong

Essayez de forcer cet index:

SELECT `user_metrics`.*
FROM `user_metrics` FORCE INDEX (index_user_metrics_on_user_id)
WHERE (`user_metrics`.user_id IN (N,N,N,N,N,N,N,N,N,N,N,N))

Je viens de vérifier, il utilise un index sur exactement la même requête:

EXPLAIN EXTENDED
SELECT * FROM tests WHERE (test IN ('test 1', 'test 2', 'test 3', 'test 4', 'test 5', 'test 6', 'test 7', 'test 8', 'test 9'))

1, 'SIMPLE', 'tests', 'range', 'ix_test', 'ix_test', '602', '', 9, 100.00, 'Using where'
13
Quassnoi

Parfois, MySQL n'utilise pas d'index, même s'il en existe un. Cela se produit lorsque l'optimiseur estime que l'utilisation de l'index nécessiterait que MySQL accède à un très grand pourcentage des lignes de la table. (Dans ce cas, une analyse de table sera probablement beaucoup plus rapide car elle nécessite moins de recherches.)

Quel pourcentage de lignes correspond à votre clause IN?

7
mluebke

Je sais que je suis en retard pour la fête. Mais j'espère pouvoir aider quelqu'un d'autre avec un problème similaire.

Dernièrement, j'ai le même problème. Ensuite, je décide d'utiliser l'auto-jointure-chose pour résoudre mon problème ... Le problème n'est pas MySQL. Le problème est nous. Le type de retour de la sous-requête est différent de notre table. Nous devons donc convertir le type de sous-requête en type de colonne de sélection . Voici un exemple de code:

select `user_metrics`.* 
from `user_metrics` um 
join (select `user_metrics`.`user_id` in (N, N, N, N) ) as temp 
on um.`user_id` = temp.`user_id`

Ou mon propre code:

Ancien: (pas d'index d'utilisation: ~ 4s)

SELECT 
    `jxm_character`.*
FROM
    jxm_character
WHERE
    information_date IN (SELECT DISTINCT
            (information_date)
        FROM
            jxm_character
        WHERE
            information_date >= DATE_SUB('2016-12-2', INTERVAL 7 DAY))
        AND `jxm_character`.`ranking_type` = 1
        AND `jxm_character`.`character_id` = 3146089;

Nouveau: (Utiliser l'indice: ~ 0.02s)

SELECT 
    *
FROM
    jxm_character jc
        JOIN
    (SELECT DISTINCT
        (information_date)
    FROM
        jxm_character
    WHERE
        information_date >= DATE_SUB('2016-12-2', INTERVAL 7 DAY)) AS temp 
        ON jc.information_date = STR_TO_DATE(temp.information_date, '%Y-%m-%d')
        AND jc.ranking_type = 1
        AND jc.character_id = 3146089;

jxm_character:

  • Records: ~ 3.5M
  • PK: jxm_character (information_date, ranking_type, character_id)

SHOW VARIABLES LIKE '%version%';

'protocol_version', '10'
'version', '5.1.69-log'
'version_comment', 'Source distribution'

Dernière remarque: assurez-vous de bien comprendre la règle d'index MySQL la plus à gauche.

P/s: Désolé pour mon mauvais anglais. Je poste mon code (production, bien sûr) pour clarifier ma solution: D.

3
Liem Le

Cela va-t-il mieux si vous supprimez les crochets redondants autour de la clause where?

Même si vous n’avez que 200 lignes environ, il se peut qu’un contrôle de table soit plus rapide. Essayez avec une table avec plus d'enregistrements.

0
Paul Tomblin