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.
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'
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?
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:
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.
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.