2009-04-28 5 views
34

J'ai (par exemple) un indice:Un index multi-colonnes fonctionne-t-il également pour les sélections sur une seule colonne?

CREATE INDEX someIndex ON orders (customer, date); 

Est-ce que cet indice n'accélérer les requêtes où client et la date sont utilisés ou faut-il accélérer les requêtes pour une seule colonne comme ça aussi?

SELECT * FROM orders WHERE customer > 33; 

J'utilise SQLite.


Si la réponse est oui, pourquoi est-il possible de créer plus d'un index par table? Encore une autre question: À quel point un index combiné est-il plus rapide que deux index séparés lorsque vous utilisez les deux colonnes dans une requête?

Répondre

32

marc_s. La première clé d'un index à plusieurs clés peut fonctionner comme un seul index de clé, mais pas les autres. En ce qui concerne la rapidité avec laquelle l'indice composite dépend de vos données et de la façon dont vous structurez votre index et vos requêtes, il est généralement important. Les index permettent essentiellement à Sqlite de faire une recherche binaire sur les champs.

En utilisant l'exemple que vous avez donné si vous avez exécuté la requête:

SELECT * from orders where customer > 33 && date > 99 

SQLite serait d'abord obtenir tous les résultats en utilisant une recherche binaire sur toute la table où le client> 33. Ensuite, il ferait une recherche binaire uniquement ces résultats recherchent la date> 99.

Si vous avez fait la même requête avec deux index séparés sur le client et la date, Sqlite devrait chercher deux fois le tableau entier, d'abord pour le client et encore pour la date.

Ainsi, le pourcentage d'augmentation de vitesse dépend de la façon dont vous structurez votre index en fonction de votre requête. Idéalement, le premier champ de votre index et votre requête devrait être celui qui élimine le plus de correspondances possibles car cela donnera la plus grande augmentation de vitesse en réduisant considérablement la quantité de travail que la deuxième recherche doit faire.

Pour plus d'informations, voir ceci: http://www.sqlite.org/optoverview.html

+2

SQLite n'utilisera PAS la deuxième colonne d'un index si la première colonne était une expression d'inégalité (par exemple client> 33). (La plupart des moteurs de base de données seraient durs). – vmatyi

+1

Si vous créez deux index distincts, un seul d'entre eux sera utilisé, l'autre sera évaluée sur l'ensemble de résultats généré par le premier. (sur un Oracle, il peut exécuter les deux recherches d'index et croiser les ensembles de résultats, si l'optimisation est basée sur les coûts et si certains critères sont réunis, mais c'est un cas rare). – vmatyi

5

Je suis assez sûr que cela fonctionnera, oui - il le fait dans MS SQL Server de toute façon.

Toutefois, cet index ne vous aide pas si vous devez sélectionner uniquement la date, par ex. une plage de dates. Dans ce cas, vous devrez peut-être créer un deuxième index uniquement sur la date pour rendre ces requêtes plus efficaces. a la bonne réponse à votre première question

Marc

+0

Merci, c'est là que je n'étais pas sûr. Je vais créer deux index distincts dans ce cas. –

3

I index utilisent couramment combinés pour trier par données que je souhaite pagine ou demande « streamily ».

En supposant qu'un client peut effectuer plus d'une commande .. et qu'il existe des clients de 0 à 11 et qu'il y a plusieurs commandes par client toutes insérées dans un ordre aléatoire. Je veux trier une requête en fonction du numéro de client suivi de la date. Vous devez également trier le champ id pour diviser les ensembles où un client a plusieurs dates identiques (même si cela peut ne jamais arriver).

sqlite> CREATE INDEX customer_asc_date_asc_index_asc ON orders 
      (customer ASC, date ASC, id ASC); 

Get page 1 d'une requête triée (limité à 10 articles):

sqlite> SELECT id, customer, date FROM orders 
      ORDER BY customer ASC, date ASC, id ASC LIMIT 10; 

2653|1|1303828585 
2520|1|1303828713 
2583|1|1303829785 
1828|1|1303830446 
1756|1|1303830540 
1761|1|1303831506 
2442|1|1303831705 
2523|1|1303833761 
2160|1|1303835195 
2645|1|1303837524 

Obtenez la page suivante:

sqlite> SELECT id, customer, date FROM orders WHERE 
      (customer = 1 AND date = 1303837524 and id > 2645) OR 
      (customer = 1 AND date > 1303837524) OR 
      (customer > 1) 
      ORDER BY customer ASC, date ASC, id ASC LIMIT 10; 

2515|1|1303837914 
2370|1|1303839573 
1898|1|1303840317 
1546|1|1303842312 
1889|1|1303843243 
2439|1|1303843699 
2167|1|1303849376 
1544|1|1303850494 
2247|1|1303850869 
2108|1|1303853285 

Et ainsi de suite ...

Avoir les index en place réduit l'analyse de l'index côté serveur lorsque vous utiliseriez une requête OFFSET couplée à une LIMIT. Le temps d'interrogation devient plus long et les disques recherchent plus le décalage est élevé. L'utilisation de cette méthode élimine cela.

L'utilisation de cette méthode est conseillée si vous envisagez de joindre des données ultérieurement, mais que vous avez seulement besoin d'un ensemble limité de données par requête. Joignez-vous à un SUBSELECT comme décrit ci-dessus pour réduire la charge de mémoire pour les grandes tables.

+0

Cela permet également d'éliminer les temps de commande côté serveur inutiles ... si vous deviez utiliser ** datetime (date, 'unixepoch', 'localtime') ** au lieu de ** date ** comme colonne de retour .. il serait assurément être limité. Je crois que ce serait de toute façon - dépend du moteur. – whardier

Questions connexes