2010-10-20 4 views
2

Je lis des index dans mon livre de base de données et je me demandais si j'avais raison dans ma supposition qu'une clause WHERE avec une expression non constante n'utiliserait pas l'index. Donc, si j'aiPerformance de l'index avec clause WHERE dans SQL

SELECT * FROM statuses WHERE app_user_id % 10 = 0; 

Ce ne serait pas utiliser un index créé sur app_user_id. Mais

SELECT * FROM statuses WHERE app_user_id = 5; 

utiliserait l'index sur app_user_id.

Répondre

5

Habituellement (il existe d'autres options), un index de base de données est un arbre B, ce qui signifie que vous pouvez faire des balayages de plage (y compris des balayages d'égalité).

La condition app_user_id % 10 = 0 ne peut pas être évaluée avec un seul balayage de plage, ce qui explique pourquoi une base de données n'utilisera probablement pas d'index.

Il pourrait encore décider d'utiliser l'index d'une autre manière, à savoir pour un balayage complet: Lire l'ensemble de la table prend plus de temps que de simplement lire l'index entier. D'un autre côté, après avoir lu l'index, vous pourrez peut-être revenir à la table, de sorte que le coût global pourrait finir par être plus élevé.

Il appartient à l'optimiseur de requêtes de base de données de décider.

Quelques exemples:

select app_user_id from t where app_user_id % 10 = 0 

Ici, vous n'avez pas besoin de la table du tout, toutes les données nécessaires dans l'index. La base de données effectuera très probablement une analyse d'index complète.

select count(*) from t where app_user_id % 10 = 0 

Identique. Balayage d'index complet.

select count(*) from t 

Seulement si app_user_id est NOT NULL cela peut être fait avec l'index (parce que les données NULL est pas dans l'index, au moins sur Oracle, au moins sur les index de colonne unique, votre base de données peut gérer cela différemment).

Certaines bases de données n'ont pas besoin d'accéder à la table ou à l'index pour cela, elles maintiennent le nombre de lignes dans les métadonnées.

select * from t where app_user_id = 5 

Ceci est le scénario classique pour un index. La base de données peut regarder la petite section de l'arbre d'index, récupérer un petit nombre (juste un s'il s'agissait d'un index unique ou primaire) de rowids et les extraire sélectivement de la table.

select * from t where app_user_id between 5 and 10 

Un autre cas d'index classique. L'analyse de plage dans l'arbre renvoie un petit nombre de rowids à extraire de la table.

select * from t where app_user_id between 5 and 10 order by app_user_id 

Depuis le retour des analyses d'index des données, vous avez commandé obtenir même le tri gratuitement.

select * from t where app_user_id between 5 and 1000000000 

Vous ne devriez peut-être pas utiliser d'index ici. Il semble correspondre à trop d'enregistrements. C'est un cas où avoir des variables de liaison masquer la plage de la base de données pourrait en fait être préjudiciable.

select * from t where app_user_id between 5 and 1000000000 
    order by app_user_id 

Mais ici, étant donné que le tri serait très coûteux (même en prenant l'espace disque de swap temporaire), peut-être pour itérer d'index est bon. Peut être.

select * from t where app_user_id % 10 = 0 

Ceci est difficile à décider. Nous avons besoin de toutes les colonnes, donc en fin de compte, la requête doit toucher la table. La question est de savoir s'il faut d'abord passer par un index. La requête renvoie environ 10% de la table entière. C'est probablement trop pour qu'un chemin d'accès à un index soit efficace. Si l'optimiseur a des raisons de croire que la requête renvoie beaucoup moins de 10% de la table, une analyse d'index suivie d'un accès à la table peut être bonne. Idem si la table est très fragmentée (beaucoup de lignes supprimées mangeant de l'espace).

+0

Donc, fondamentalement, votre réponse indique que cela dépend de la base de données. –

+0

et les données. et les options de configuration. En outre, peu importe si un index est utilisé ou non. Il importe seulement que ce soit plus rapide que d'autres alternatives. Dans tous les cas, votre raisonnement devrait être "quelles requêtes dois-je exécuter" et ensuite concevoir le schéma et les index en conséquence. Si votre requête% 10 ne fonctionne pas assez bien, vous devrez peut-être dénormaliser la colonne ou créer un index fonctionnel. – Thilo