150 votes

Quand dois-je utiliser un indice composite ?

  1. Quand dois-je utiliser un indice composite dans une base de données?
  2. Quelles sont les performances de la fourche à l'aide d'un indice composite)?
  3. Pourquoi devrais-je utiliser un indice composite?

Par exemple, j'ai un homes tableau:

CREATE TABLE IF NOT EXISTS `homes` (
  `home_id` int(10) unsigned NOT NULL auto_increment,
  `sqft` smallint(5) unsigned NOT NULL,
  `year_built` smallint(5) unsigned NOT NULL,
  `geolat` decimal(10,6) default NULL,
  `geolng` decimal(10,6) default NULL,
  PRIMARY KEY  (`home_id`),
  KEY `geolat` (`geolat`),
  KEY `geolng` (`geolng`),
) ENGINE=InnoDB  ;

Est-il judicieux pour moi d'utiliser un indice composite pour les deux geolat et geolng, tels que:

- Je le remplacer:

  KEY `geolat` (`geolat`),
  KEY `geolng` (`geolng`),

avec:

KEY `geolat_geolng` (`geolat`, `geolng`)

Si oui:

  • Pourquoi?
  • Qu'est-ce que la performance de la ramification à l'aide d'un indice composite)?

Mise à JOUR:

Puisque beaucoup de gens ont déclaré entièrement tributaire des requêtes-je effectuer, ci-dessous est la requête la plus courante effectuée:

SELECT * FROM homes
WHERE geolat BETWEEN ??? AND ???
AND geolng BETWEEN ??? AND ???

Mise à JOUR 2:

À la suite de schéma de base de données:

CREATE TABLE IF NOT EXISTS `homes` (
  `home_id` int(10) unsigned NOT NULL auto_increment,
  `primary_photo_group_id` int(10) unsigned NOT NULL default '0',
  `customer_id` bigint(20) unsigned NOT NULL,
  `account_type_id` int(11) NOT NULL,
  `address` varchar(128) collate utf8_unicode_ci NOT NULL,
  `city` varchar(64) collate utf8_unicode_ci NOT NULL,
  `state` varchar(2) collate utf8_unicode_ci NOT NULL,
  `zip` mediumint(8) unsigned NOT NULL,
  `price` mediumint(8) unsigned NOT NULL,
  `sqft` smallint(5) unsigned NOT NULL,
  `year_built` smallint(5) unsigned NOT NULL,
  `num_of_beds` tinyint(3) unsigned NOT NULL,
  `num_of_baths` decimal(3,1) unsigned NOT NULL,
  `num_of_floors` tinyint(3) unsigned NOT NULL,
  `description` text collate utf8_unicode_ci,
  `geolat` decimal(10,6) default NULL,
  `geolng` decimal(10,6) default NULL,
  `display_status` tinyint(1) NOT NULL,
  `date_listed` timestamp NOT NULL default CURRENT_TIMESTAMP,
  `contact_email` varchar(100) collate utf8_unicode_ci NOT NULL,
  `contact_phone_number` varchar(15) collate utf8_unicode_ci NOT NULL,
  PRIMARY KEY  (`home_id`),
  KEY `customer_id` (`customer_id`),
  KEY `city` (`city`),
  KEY `num_of_beds` (`num_of_beds`),
  KEY `num_of_baths` (`num_of_baths`),
  KEY `geolat` (`geolat`),
  KEY `geolng` (`geolng`),
  KEY `account_type_id` (`account_type_id`),
  KEY `display_status` (`display_status`),
  KEY `sqft` (`sqft`),
  KEY `price` (`price`),
  KEY `primary_photo_group_id` (`primary_photo_group_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=8 ;

À l'aide de l'instruction SQL suivante:

EXPLAIN SELECT  homes.home_id,
    				address,
    				city,
    				state,
    				zip,
    				price,
    				sqft,
    				year_built,
    				account_type_id,
    				num_of_beds,
    				num_of_baths,
    				geolat,
    				geolng,
    				photo_id,
    				photo_url_dir
    		FROM homes
    		LEFT OUTER JOIN home_photos ON homes.home_id = home_photos.home_id
    			AND homes.primary_photo_group_id = home_photos.home_photo_group_id
    			AND home_photos.home_photo_type_id = 2
    		WHERE homes.display_status = true
    		AND homes.geolat BETWEEN -100 AND 100
    		AND homes.geolng BETWEEN -100 AND 100

EXPLIQUER retourne:

id  select_type  table        type  possible_keys                                    key                  key_len  ref     rows  Extra
----------------------------------------------------------------------------------------------------------
1   SIMPLE       homes        ref   geolat,geolng,display_status                     display_status       1        const   2     Using where
1  SIMPLE        home_photos  ref   home_id,home_photo_type_id,home_photo_group_id   home_photo_group_id  4        homes.primary_photo_group_id   4

Je n'arrive pas à comprendre comment lire la commande explain. Ne ce look de bon ou de mauvais. Maintenant, je ne suis PAS à l'aide d'un indice composite de geolat et geolng. Dois-je être?

118voto

Mark Canlas Points 4698

Vous devez utiliser un indice composite lorsque vous utilisez les requêtes qui en bénéficient. Un indice composite qui ressemble à ceci:

index( column_A, column_B, column_C )

bénéficieront d'une requête qui utilise ces champs pour rejoindre, de filtrage, et parfois la sélection. Il permettra également de bénéficier des requêtes qui utilisent le plus à gauche des sous-ensembles de colonnes dans le composite. Si l'index ci-dessus permet également de satisfaire les requêtes

index( column_A, column_B, column_C )
index( column_A, column_B )
index( column_A )

Mais il ne sera pas (du moins pas directement, peut-être que ça peut aider partiellement si il n'y a pas de meilleurs indices) de l'aide pour les requêtes

index( column_A, column_C )

Remarquez comment column_B est manquant.

Dans votre exemple, un indice composite de deux dimensions seront pour la plupart profit des requêtes requête sur les deux dimensions ou le plus à gauche de la dimension par lui-même, mais pas la dimension la plus à droite par lui-même. Si vous êtes toujours l'interrogation de deux dimensions, un indice composite est le chemin à parcourir, n'a pas vraiment d'importance, qui est le premier (plus probablement).

62voto

Emre Yazıcı Points 5413

Imaginez que vous avez les trois requêtes ci-dessous:

Requête I:

SELECT * FROM homes WHERE `geolat`=42.9 AND `geolng`=36.4

Requête II:

SELECT * FROM homes WHERE `geolat`=42.9

Requête III:

SELECT * FROM homes WHERE `geolng`=36.4

Si vous avez séparée de l'indice par colonne, tous les trois requêtes utiliser les index. Dans MySQL, si vous avez de l'indice composite (geolat, geolng), la requête ne je de requête et II (qui est à l'aide de la première partie de l'indice composite) utilise les index. Dans ce cas, la requête III exige complète de la table de recherche.

Sur les Index de Plusieurs Colonnes de la section de manuel, il est clairement expliqué comment plusieurs index de colonne de travail, donc je ne veux pas avoir à retaper manuel.

À partir du Manuel de Référence de MySQL page:

Un index multi-colonnes peut être considéré comme un tableau trié contenant les valeurs qui sont créés par la concaténation des valeurs de la des colonnes indexées.

Si vous utilisez séparés index pour geolat et geolng colonnes, vous avez deux index différents dans votre tableau dans lequel vous pouvez effectuer une recherche indépendante.

INDEX geolat
-----------
VALUE RRN
36.4  1
36.4  8
36.6  2
37.8  3
37.8  12
41.4  4

INDEX geolng
-----------
VALUE RRN
26.1  1
26.1  8
29.6  2
29.6  3
30.1  12
34.7  4

Si vous utilisez de l'indice composite vous avez un seul indice pour les deux colonnes:

INDEX (geolat, geolng)
-----------
VALUE      RRN
36.4,26.1  1
36.4,26.1  8
36.6,29.6  2
37.8,29.6  3
37.8,30.1  12
41.4,34.7  4

Le RRN est relatif numéro d'enregistrement (pour simplifier, on peut dire l'ID). Les deux premiers index généré séparée et le troisième indice composite. Comme vous pouvez le voir, vous pouvez faire une recherche basée sur geolng sur composite puisqu'il est indexé par geolat, cependant il est possible de rechercher par geolat ou "geolat ET geolng" (depuis geolng est le deuxième niveau de l'indice).

Aussi, jetez un oeil à Comment MySQL Utilise les Index manuel de la section.

19voto

Question Overflow Points 2375

Il pourrait y avoir un malentendu à propos de ce que l'indice composite. Beaucoup de gens pensent que l'indice composite peut être utilisé pour optimiser une requête de recherche aussi longtemps que l' where clause couvre les colonnes indexées, dans votre cas geolat et geolng. Poussons plus loin:

Je crois que vos données sur les coordonnées des maisons seraient aléatoires décimales en tant que tel:

home_id  geolat  geolng
   1    20.1243  50.4521
   2    22.6456  51.1564
   3    13.5464  45.4562
   4    55.5642 166.5756
   5    24.2624  27.4564
   6    62.1564  24.2542
...

Depuis geolat et geolng valeurs peine à se répéter. Un indice composite sur geolat et geolng ressemblerait à quelque chose comme ceci:

index_id  geolat  geolng
   1     20.1243  50.4521
   2     20.1244  61.1564
   3     20.1251  55.4562
   4     20.1293  66.5756
   5     20.1302  57.4564
   6     20.1311  54.2542
...

Par conséquent, la deuxième colonne de l'indice composite est fondamentalement inutile! La vitesse de votre requête avec un indice composite est probablement va être similaire à un indice sur l' geolat colonne.

Comme mentionné par la Volonté, MySQL fournit de l' extension spatiale de soutien. Spatiale point est stocké dans une colonne unique au lieu de deux sous - lat lng colonnes. Index Spatial peut être appliquée à une colonne de ce type. Cependant, l'efficacité pourrait être surestimé basé sur mon expérience personnelle. Il se pourrait que d'un index spatial ne permet pas de résoudre les deux dimensions du problème, mais seulement d'accélérer la recherche à l'aide de R-Arbres avec quadratique de fractionnement.

Le compromis est que spatiale point consomme beaucoup plus de mémoire qu'il a utilisé huit octets de nombres double précision pour le stockage des coordonnées. Corrigez-moi si je me trompe.

5voto

ProfileTwist Points 878

Les indices composites sont très puissants, car ils:

  • Faire respecter l'intégrité de la structure
  • Activer le tri sur un FILTRÉE id

FAIRE RESPECTER L'INTÉGRITÉ DE LA STRUCTURE

Les indices composites ne sont pas seulement un autre type d'indice; ils peuvent fournir une structure NÉCESSAIRE à une table en application de l'intégrité de la Clé Primaire.

Mysql Innodb prend en charge le clustering et l'exemple suivant illustre pourquoi un indice composite peut être nécessaire.

Pour créer un amis tables (par exemple, pour un réseau social) nous avons besoin de 2 colonnes: user_id, friend_id.

Tableau Strcture

user_id (medium_int)
friend_id (medium_int)

Primary Key -> (user_id, friend_id)

Par la vertu, une Clé Primaire (PK) est unique et par la création d'un composite PK, Innodb va automatiquement vérifier que pas de doublons sur user_id, friend_id existe lorsqu'un nouvel enregistrement est ajouté. C'est le comportement attendu qu'aucun utilisateur ne devrait avoir plus que 1 dossier (lien de parenté) avec friend_id = 2 par exemple.

Sans un composite PK, nous pouvons créer ce schéma à l'aide d'une clé de substitution:

user_friend_id
user_id
friend_id

Primary Key -> (user_friend_id)

Maintenant, chaque fois qu'un nouvel enregistrement est ajouté il nous faudra vérifier qu'un enregistrement précédent avec la combinaison user_id, friend_id n'existe pas déjà.

En tant que tel, un indice composite peut faire respecter l'intégrité de la structure.

ACTIVER LE TRI SUR UN FILTRÉE ID

Il est très commun pour trier un ensemble de documents par la poste temps (timestamp ou datetime). Habituellement, cela signifie que l'affichage sur un identifiant donné. Voici un exemple

Tableau User_Wall_Posts (pense que si Facebook de messages sur le mur)

user_id (medium_int)
timestamp (timestamp)
author_id (medium_int)
comment_post (text)

Primary Key -> (user_id, timestamp, author_id)

Nous voulons interroger et trouver tous les messages de user_id = 10 et de trier les commentaires des articles par timestamp (date).

REQUÊTE SQL

SELECT * FROM User_Wall_Posts WHERE user_id = 10 ORDER BY timestamp DES

Le composite PK Mysql permet de filtrer et trier les résultats à l'aide de l'index; Mysql n'aurez pas à utiliser un fichier temporaire ou filesort pour aller chercher les résultats. Sans une clé composite, ce ne serait pas possible et serait la cause d'une très inefficace de la requête.

En tant que tel, les clés composites sont très puissants et un costume plus que le simple problème de "je veux à la recherche d' column_a, column_b donc je vais utiliser des clés composites. Pour mon schéma de base de données, j'ai comme beaucoup de clés composites comme de simples touches. Ne négligez pas une clé composite de l'utiliser!

1voto

Mitch Wheat Points 169614

Il n'y a pas de Noir et Blanc, taille unique réponse.

Vous devez utiliser un indice composite, lors de votre charge de travail de requête serait à l'avantage de celui-ci.

Vous avez besoin de faire connaître votre requête charge de travail afin de le déterminer.

Un indice composite entre en jeu lorsque les requêtes peuvent être entièrement satisfait de cet indice.

Mise à JOUR (en réponse à modifier à la question posée): Si vous sélectionnez * à partir de la table de l'indice composite peut être utilisé, il ne peut pas. Vous devez exécuter le PLAN d'EXPLIQUER pour être sûr.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X