2009-06-26 10 views
42

En ActiveRecord il y a deux façons de déclarer les index pour plusieurs colonnes:Index pour plusieurs colonnes dans ActiveRecord

add_index :classifications, [:species, :family, :trivial_names]
add_index :classifications, :species 
add_index :classifications, :family 
add_index :classifications, :trivial_names

est-il une différence entre la première approche et le second? Si oui, quand dois-je utiliser le premier et le second?

+0

Merci, Collimarco, d'avoir choisi ma réponse comme "la réponse". –

Répondre

84

Vous comparez un indice composite avec un ensemble d'indices indépendants. Ils sont juste différents. Pensez-y de cette façon: un index composé vous donne une recherche rapide du premier champ dans un ensemble imbriqué de champs suivi par une recherche rapide du deuxième champ dans SEULEMENT les enregistrements déjà sélectionnés par le premier champ, suivi d'une recherche rapide du troisième champ - encore, seulement dans les enregistrements sélectionnés par les deux indices précédents.

Prenons un exemple. Votre moteur de base de données ne prendra pas plus de 20 étapes pour localiser une valeur unique dans 1 000 000 enregistrements (si la mémoire le permet) si vous utilisez un index. Cela est vrai que vous utilisiez un index composite ou indépendant - mais UNIQUEMENT pour le premier champ ("espèce" dans votre exemple bien que je pense que vous voulez Famille, Espèce, puis Nom commun). Maintenant, disons qu'il y a 100 000 enregistrements correspondants pour cette première valeur de champ. Si vous n'avez que des index uniques, alors toute recherche dans ces enregistrements prendra 100 000 pas: un pour chaque enregistrement récupéré par le premier index. C'est parce que le deuxième index ne sera pas utilisé (dans la plupart des bases de données - c'est un peu une simplification) et une correspondance de force brute doit être utilisée.

Si vous avez un indice composite alors votre recherche est beaucoup plus rapide parce que votre deuxième recherche sur le terrain aura un indice au sein le premier ensemble de valeurs. Dans ce cas, vous n'avez pas besoin de plus de 17 étapes pour atteindre votre première valeur correspondante dans le champ 2 dans les 100 000 correspondances du champ 1 (base de journal 2 sur 100 000). Donc: étapes nécessaires pour trouver un enregistrement unique d'une base de données de 1.000.000 enregistrements utilisant un index composite sur 3 champs imbriqués où le premier récupère 100.000 et le second récupère 10.000 = 20 + 17 + 14 = 51 étapes.

Étapes nécessaires dans les mêmes conditions avec seulement des indices indépendants = 20 + 100 000 + 10 000 = 110 020 pas.

Grande différence, hein?

Maintenant, ne pas allez écrous mettre des indices composites partout. D'abord, ils sont chers sur les insertions et les mises à jour. Deuxièmement, ils ne sont utilisés que si vous recherchez réellement des données imbriquées (pour un autre exemple, je les utilise pour extraire des données pour les connexions d'un client sur une plage de dates donnée). En outre, ils ne valent pas la peine si vous travaillez avec des ensembles de données relativement petits.

Enfin, vérifiez la documentation de votre base de données. Les bases de données sont devenues extrêmement sophistiquées dans la capacité de déployer des index ces jours-ci et le scénario Database 101 décrit ci-dessus peut ne pas convenir à certains (bien que je développe toujours comme si je le sais).

+0

Merci pour l'explication! Voyez ce que j'ai demandé à M. Matt: la clause WHERE contient OU. Dans ce cas, est-ce utile un indice composé? Je dirais non, car la base de données doit toujours rechercher tous les éléments et pas seulement les lignes qui résultent de la première condition (cela aurait été différent s'il y avait l'opérateur AND parce qu'il "filtre" les lignes et réduit la portée) . Ai-je tort? – collimarco

+3

collimarco - dans l'exemple que vous fournissez à M. Matt, les indices indépendants fourniraient de meilleures performances car chacun serait utilisé indépendamment dans le cadre du plan d'exécution SQL. Pensez-y de cette façon: AND est compositionnel, OU est indépendant. Pour donner un autre exemple, si votre clause where était "WHERE (Famille = X AND Species = Y) OR (CommonName = Z)", vous voudriez un index composite sur Family | Species et un index indépendant sur CommonName. –

+0

BTW: Les plans d'exécution SQL sont disponibles dans des bases de données plus sophistiquées telles que SQL Server et Oracle et peuvent être très utiles en tant qu'outil pédagogique (pour vous aider à voir ce qui se passe sous les couvertures). comme un mécanisme pour tester diverses stratégies d'indexation. –

1

From the docs:

Lors de la création d'un index sur plusieurs colonnes , la première colonne est utilisée comme un nom pour l'index. Par exemple, lorsque vous spécifiez un index sur deux colonnes [: first,: last], le SGBD crée un index pour les deux colonnes ainsi qu'un index pour la première colonne: premier. Utiliser simplement le prénom pour cet indice est logique, car vous aurez jamais besoin de créer un index singulier avec ce nom.

Utilisez la première méthode lors de la création d'un index composé et la seconde lors de la création d'index sur des attributs uniques.

Il existe quelques bons points here on when to use compound indexes, mais l'essentiel est qu'ils sont bons en utilisant un où sur plusieurs attributs. Notez qu'ils doivent être utilisés avec d'autres index (indexez toujours vos clés) et non comme un remplacement.

+0

Merci! Mais ... quand est-il sensé d'utiliser un index composé au lieu d'un index sur un seul attribut? Pouvez-vous me donner quelques exemples? – collimarco

+0

Mis à jour ma réponse – Codebeef

+0

Vous avez dit de ne pas les utiliser en remplacement, mais si je les utilise uniquement dans cette requête: SELECT * FROM classifications O WH espèces LIKE '% sth%' OU famille LIKE '% sth%' OU trivial_names LIKE '% sth%' Dans ce cas, est-il correct d'utiliser uniquement l'index composé? – collimarco

10

Les deux approches sont différentes. Le premier crée un index unique sur trois attributs, le second crée trois index à un seul attribut. Les besoins de stockage seront différents, bien que sans distributions, il n'est pas possible de dire lequel serait le plus grand.

L'indexation de trois colonnes [A, B, C] fonctionne bien lorsque vous devez accéder aux valeurs de A, A + B et A + B + C. Il ne sera pas bon si votre requête (ou de trouver des conditions ou autre) ne référence pas A.

Lorsque A, B et C sont indexés séparément, certains optimiseurs de requête DBMS envisageront de combiner deux ou plusieurs indices (sujet à l'estimation de l'optimiseur de l'efficacité) pour donner un résultat similaire à un seul indice multi-colonnes.

Supposons que vous ayez un système de commerce électronique. Vous souhaitez interroger les commandes par purchase_date, customer_id et parfois les deux. Je commencerais par créer deux indices: un pour chaque attribut. En revanche, si vous spécifiez toujours purchase_date et customer_id, un seul index sur les deux colonnes sera probablement le plus efficace. La commande est significative: si vous souhaitez également interroger des commandes pour toutes les dates d'un client, placez le paramètre customer_id dans la première colonne de l'index.

Questions connexes