- Quand dois-je utiliser un index composite dans une base de données?
- Quelle est la ramification des performances en utilisant un index composite)?
- Pourquoi devrais-je utiliser un index composite?
Par exemple, j'ai une homes
table:
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 index composite pour les deux geolat
et geolng
, tel que:
Je remplace:
KEY `geolat` (`geolat`),
KEY `geolng` (`geolng`),
avec:
KEY `geolat_geolng` (`geolat`, `geolng`)
Si c'est le cas:
- Pourquoi?
- Quelle est la ramification des performances en utilisant un index composite)?
METTRE À JOUR:
Étant donné que de nombreuses personnes l'ont déclaré entièrement dépendant des requêtes que j'effectue, voici la requête la plus courante effectuée:
SELECT * FROM homes
WHERE geolat BETWEEN ??? AND ???
AND geolng BETWEEN ??? AND ???
MISE À JOUR 2:
Avec le schéma de base de données suivant:
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 ;
En utilisant le SQL suivant:
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
EXPLAIN renvoie:
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 ne comprends pas très bien comment lire la commande EXPLAIN. Cela semble-t-il bon ou mauvais. À l'heure actuelle, je n'utilise PAS un index composite pour geolat et geolng. Dois-je l'être?
WHERE geolat BETWEEN ??? AND ??? AND geolng BETWEEN ??? AND ???
. Il s'arrêtera après le premier champ. La réponse de "Question Overflow" explique pourquoi.Imaginez que vous ayez les trois requêtes suivantes:
Requête I:
Requête II:
Requête III:
Si vous avez un index séparé par colonne, les trois requêtes utilisent des index. Dans MySQL, si vous avez un index composite (
geolat
,geolng
), seules les requêtes I et II (qui utilisent la première partie de l'index composite) utilisent des index. Dans ce cas, la requête III nécessite une recherche complète dans la table.Dans la section Index à colonnes multiples du manuel, il est clairement expliqué comment fonctionnent les index à colonnes multiples, donc je ne veux pas retaper le manuel.
Depuis la page du manuel de référence MySQL :
Si vous utilisez un index séparé pour les colonnes geolat et geolng, vous avez deux index différents dans votre table que vous pouvez rechercher indépendamment.
Si vous utilisez un index composite, vous n'avez qu'un seul index pour les deux colonnes:
RRN est le numéro d'enregistrement relatif (pour simplifier, vous pouvez dire ID). Les deux premiers index générés séparément et le troisième index est composite. Comme vous pouvez le voir, vous pouvez effectuer une recherche basée sur geolng sur composite car il est indexé par geolat, mais il est possible de rechercher par geolat ou "geolat AND geolng" (puisque geolng est un index de deuxième niveau).
Jetez également un œil à la section du manuel Comment MySQL utilise les index .
la source
BETWEEN
), aucun autre champ de l'index n'est pris en compte! L'indice composite n'est donc pas meilleur.Il pourrait y avoir une idée fausse sur ce que fait l'index composite. Beaucoup de gens pensent que l'index composite peut être utilisé pour optimiser une requête de recherche tant que la
where
clause couvre les colonnes indexées, dans votre casgeolat
etgeolng
. Allons plus loin:Je crois que vos données sur les coordonnées des maisons seraient des décimales aléatoires en tant que telles:
Depuis
geolat
et lesgeolng
valeurs se répètent à peine. Un index composite surgeolat
etgeolng
ressemblerait à quelque chose comme ceci:Par conséquent, la deuxième colonne de l'indice composite est fondamentalement inutile ! La vitesse de votre requête avec un index composite sera probablement similaire à celle d'un index sur la
geolat
colonne uniquement .Comme mentionné par Will, MySQL fournit un support d' extension spatiale . Un point spatial est stocké dans une seule colonne au lieu de deux
lat
lng
colonnes séparées . L'indice spatial peut être appliqué à une telle colonne. Cependant, l'efficacité pourrait être surfaite en fonction de mon expérience personnelle. Il se peut que l'index spatial ne résout pas le problème bidimensionnel mais accélère simplement la recherche en utilisant des R-Trees avec division quadratique .Le compromis est qu'un point spatial consomme beaucoup plus de mémoire car il utilise des nombres à double précision de huit octets pour stocker les coordonnées. Corrigez-moi si je me trompe.
la source
Les index composites sont très puissants car ils:
APPLIQUER L'INTÉGRITÉ DE LA STRUCTURE
Les index composites ne sont pas simplement un autre type d'index; ils peuvent fournir la structure NÉCESSAIRE à une table en imposant l'intégrité en tant que clé primaire.
Innodb de Mysql prend en charge le clustering et l'exemple suivant illustre pourquoi un index composite peut être nécessaire.
Pour créer un amis tables (pour un réseau social) nous avons besoin de 2 colonnes:
user_id, friend_id
.Structure de la table
En vertu, une clé primaire (PK) est unique et en créant une PK composite, Innodb vérifiera automatiquement qu'aucun doublon
user_id, friend_id
n'existe lors de l'ajout d'un nouvel enregistrement. C'est le comportement attendu car aucun utilisateur ne doit avoir plus d'un enregistrement (lien de relation) avecfriend_id = 2
par exemple.Sans PK composite, nous pouvons créer ce schéma à l'aide d'une clé de substitution:
Maintenant, chaque fois qu'un nouvel enregistrement est ajouté, nous devrons 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 index composite peut renforcer l'intégrité de la structure.
ACTIVER LE TRI SUR UNE ID FILTRÉE
Il est très courant de trier un ensemble d'enregistrements par heure de publication (horodatage ou date / heure). Habituellement, cela signifie publier sur un identifiant donné. Voici un exemple
Table User_Wall_Posts (pensez aux messages sur le mur de Facebook)
Nous voulons interroger et trouver tous les articles pour
user_id = 10
et trier les articles de commentaire partimestamp
(date).Requête SQL
Le PK composite permet à Mysql de filtrer et de trier les résultats à l'aide de l'index; Mysql n'aura pas à utiliser un fichier temporaire ou un tri de fichiers pour récupérer les résultats. Sans une clé composite, cela ne serait pas possible et entraînerait une requête très inefficace.
En tant que telles, les clés composites sont très puissantes et conviennent plus que le simple problème de "Je veux rechercher
column_a, column_b
donc j'utiliserai des clés composites. Pour mon schéma de base de données actuel, j'ai autant de clés composites que de clés simples. N'oubliez pas l'utilisation d'une clé composite!la source
Les index composites sont utiles pour
Un index composite ne peut pas gérer deux plages. J'en discute plus en détail dans mon livre de recettes d'index .
Trouver le plus proche - Si la question concerne vraiment l' optimisation
alors aucun index ne peut vraiment gérer les deux dimensions.
Au lieu de cela, il faut «sortir des sentiers battus». Si une dimension est implémentée via le partitionnement et l'autre est implémentée en choisissant soigneusement le
PRIMARY KEY
, on peut obtenir une efficacité nettement meilleure pour les très grandes tables de recherche lat / lng. Mon dernier blog va dans les détails de la façon de mettre en œuvre "trouver le plus proche" sur le globe. Il comprend le code.Ce
PARTITIONs
sont des bandes de plages de latitude. LePRIMARY KEY
commence délibérément par la longitude afin que les lignes utiles soient probablement dans le même bloc. Une routine stockée orchestre le code désordonné pour faireorder by... limit...
et pour faire croître le «carré» autour de la cible jusqu'à ce que vous ayez suffisamment de cafés (ou autre). Il prend également en charge les calculs du grand cercle et la gestion de la ligne de date et des pôles.Plus
J'ai écrit un autre blog; il compare 5 façons de faire des recherches lat / lng: http://mysql.rjweb.org/doc.php/latlng#representation_choices (Il fait référence au lien donné ci-dessus comme l'un des 5.) Une des autres façons est la suivante, et il souligne qu'ils sont optimaux pour le cas particulier :
Autrement dit, il est important d'avoir les deux colonnes dans deux index et de ne pas avoir d'index à une seule colonne sur geolat et geolng.
la source
Il n'y a pas de réponse unique en noir et blanc.
Vous devez utiliser un index composite, lorsque la charge de travail de votre requête en bénéficierait.
Vous devez profiler la charge de travail de votre requête pour le déterminer.
Un index composite entre en jeu lorsque les requêtes peuvent être entièrement satisfaites à partir de cet index.
MISE À JOUR (en réponse à la modification de la question posée): Si vous sélectionnez * dans le tableau, l'index composite peut être utilisé, ce n'est peut-être pas le cas. Vous devrez exécuter EXPLAIN PLAN pour être sûr.
la source
Pour effectuer des recherches spatiales, vous avez besoin d'un algorithme R-Tree , qui permet de rechercher très rapidement des zones géographiques. Exactement ce dont vous avez besoin pour ce travail.
Certaines bases de données ont des index spatiaux intégrés. Une recherche rapide sur Google montre que MySQL 5 en a (qui, en regardant votre SQL, je suppose que vous utilisez MySQL).
la source
L'index composite peut être utile lorsque vous souhaitez optimiser la
group by
clause (consultez cet article http://dev.mysql.com/doc/refman/5.0/en/group-by-optimization.html ). Votre attention s'il vous plaît:la source
GROUP BY
n'a pas été mentionné.GROUP BY
n'a pas été mentionné par l'OP.Je suis avec @Mitch, dépend entièrement de vos requêtes. Heureusement, vous pouvez créer et supprimer des index à tout moment, et vous pouvez ajouter le mot clé EXPLAIN à vos requêtes pour voir si l'analyseur de requêtes utilise les index.
Si vous recherchez une paire lat / longue exacte, cet indice aurait probablement du sens. Mais vous allez probablement chercher des maisons à une certaine distance d'un endroit particulier, donc vos requêtes ressembleront à ceci (voir source ):
et l'index ne sera probablement pas utile du tout. Pour les requêtes géospatiales, vous avez besoin de quelque chose comme ça .
Mise à jour: avec cette requête:
L'analyseur de requêtes peut utiliser un index sur geolat seul, ou un index sur geolng seul, ou éventuellement les deux index. Je ne pense pas qu'il utiliserait un index composite. Mais il est facile d'essayer chacune de ces permutations sur un ensemble de données réel, puis (a) voir ce que EXPLAIN vous dit et (b) mesurer le temps que prend réellement la requête.
la source