Question

Existe-t-il un moyen d'empêcher MySQL d'effectuer une analyse complète de la table lorsque le résultat n'a pas été trouvé à l'aide d'index?

Par exemple cette requête:

SELECT *
FROM a
WHERE (X BETWEEN a.B AND a.C) 
ORDER BY a.B DESC 
LIMIT 1;

N'est efficace que si X satisfait à la condition et qu’au moins une ligne est renvoyée, mais si la condition ne peut être satisfaite par aucune donnée de la table, une analyse complète sera effectuée, ce qui peut être très coûteux.

Je ne veux pas optimiser cette requête particulière, ce n'est qu'un exemple.

EXPLAIN sur cette requête avec X dans ou en dehors de la plage:

id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE a range long_ip  long_ip 8 \N 116183 100.00 Using where

STATUS VARIABLE affiche des informations bien meilleures. Pour X en dehors de la plage:

Handler_read_prev 84181
Key_read_requests 11047

Dans la plage:

Handler_read_key 1
Key_read_requests 12

Si seulement il y avait un moyen d'empêcher Handler_read_prev de dépasser de plus de 1.

MISE À JOUR. Je ne peux pas accepter ma propre réponse car elle ne répond pas vraiment à la question (HANDLER est une fonctionnalité intéressante, cependant). Il me semble qu’il n’existe aucun moyen général d’empêcher MySQL de réaliser une analyse complète. Bien que des conditions simples telles que key = 'X' soient considérées comme "impossibles", des éléments plus complexes tels que BETWEEN ne le seront pas.

Était-ce utile?

La solution 2

Voici ce que j'ai proposé à la fin:

HANDLER a OPEN;
HANDLER a READ BC <= (X);
HANDLER a CLOSE;

BC est le nom de la clé (B, C). Si nous commandons la table par B DESC, le résultat obtenu est égal à

SELECT *
FROM a
WHERE (X BETWEEN a.B AND a.C) 
ORDER BY a.B DESC 
LIMIT 1;

Maintenant, si X n'est pas dans la plage de la table a, il suffit de vérifier que aC est supérieur à X, si ce n'est pas le cas, X est certainement en dehors de la plage et nous n'avons pas besoin de chercher plus loin. .

Ceci n’est cependant pas très élégant et vous devrez recourir au tableau à chaque insertion ou mise à jour.

Autres conseils

Vous pouvez écrire un "entièrement couvert". sous-requête qui utilise uniquement les données disponibles dans les index. En fonction de la clé primaire renvoyée, vous pouvez rechercher les lignes de la table principale.

La requête suivante est entièrement couverte par les index sur (id), (B, id) et (C, id):

select *
from a
where id in (
    select id
    from a 
    where x <= C
    and id in (
        select id
        from a
        where B <= X 
    )
)
limit 1

Chaque SELECT utilise un index: le plus à l'intérieur de l'index sur (B, id); le SELECT du milieu utilise l'index sur (C, id) et le SELECT externe utilise la clé primaire.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top