Ma situation:
Comment puis-je l'optimiser?
Voici la requête:
SELECT vehicles.make_id,
vehicles.fuel_id,
vehicles.body_id,
vehicles.transmission_id,
vehicles.colour_id,
vehicles.mileage,
vehicles.vehicle_year,
vehicles.engine_size,
vehicles.trade_or_private,
vehicles.doors,
vehicles.model_id,
Round(3959 * Acos(Cos(Radians(51.465436)) *
Cos(Radians(vehicles.gps_lat)) *
Cos(
Radians(vehicles.gps_lon) - Radians(
-0.296482)) +
Sin(
Radians(51.465436)) * Sin(
Radians(vehicles.gps_lat)))) AS distance
FROM vehicles
INNER JOIN vehicles_makes
ON vehicles.make_id = vehicles_makes.id
LEFT JOIN vehicles_models
ON vehicles.model_id = vehicles_models.id
LEFT JOIN vehicles_fuel
ON vehicles.fuel_id = vehicles_fuel.id
LEFT JOIN vehicles_transmissions
ON vehicles.transmission_id = vehicles_transmissions.id
LEFT JOIN vehicles_axles
ON vehicles.axle_id = vehicles_axles.id
LEFT JOIN vehicles_sub_years
ON vehicles.sub_year_id = vehicles_sub_years.id
INNER JOIN members
ON vehicles.member_id = members.id
LEFT JOIN vehicles_categories
ON vehicles.category_id = vehicles_categories.id
WHERE vehicles.status = 1
AND vehicles.date_from < 1330349235
AND vehicles.date_to > 1330349235
AND vehicles.type_id = 1
AND ( vehicles.price >= 0
AND vehicles.price <= 1000000 )
Voici le schéma de la table de véhicule :
CREATE TABLE IF NOT EXISTS `vehicles` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`number_plate` varchar(100) NOT NULL,
`type_id` int(11) NOT NULL,
`make_id` int(11) NOT NULL,
`model_id` int(11) NOT NULL,
`model_sub_type` varchar(250) NOT NULL,
`engine_size` decimal(12,1) NOT NULL,
`vehicle_year` int(11) NOT NULL,
`sub_year_id` int(11) NOT NULL,
`mileage` int(11) NOT NULL,
`fuel_id` int(11) NOT NULL,
`transmission_id` int(11) NOT NULL,
`price` decimal(12,2) NOT NULL,
`trade_or_private` tinyint(4) NOT NULL,
`postcode` varchar(25) NOT NULL,
`gps_lat` varchar(50) NOT NULL,
`gps_lon` varchar(50) NOT NULL,
`img1` varchar(100) NOT NULL,
`img2` varchar(100) NOT NULL,
`img3` varchar(100) NOT NULL,
`img4` varchar(100) NOT NULL,
`img5` varchar(100) NOT NULL,
`img6` varchar(100) NOT NULL,
`img7` varchar(100) NOT NULL,
`img8` varchar(100) NOT NULL,
`img9` varchar(100) NOT NULL,
`img10` varchar(100) NOT NULL,
`is_featured` tinyint(4) NOT NULL,
`body_id` int(11) NOT NULL,
`colour_id` int(11) NOT NULL,
`doors` tinyint(4) NOT NULL,
`axle_id` int(11) NOT NULL,
`category_id` int(11) NOT NULL,
`contents` text NOT NULL,
`date_created` int(11) NOT NULL,
`date_edited` int(11) NOT NULL,
`date_from` int(11) NOT NULL,
`date_to` int(11) NOT NULL,
`member_id` int(11) NOT NULL,
`inactive_id` int(11) NOT NULL,
`status` tinyint(4) NOT NULL,
PRIMARY KEY (`id`),
KEY `type_id` (`type_id`),
KEY `make_id` (`make_id`),
KEY `model_id` (`model_id`),
KEY `fuel_id` (`fuel_id`),
KEY `transmission_id` (`transmission_id`),
KEY `body_id` (`body_id`),
KEY `colour_id` (`colour_id`),
KEY `axle_id` (`axle_id`),
KEY `category_id` (`category_id`),
KEY `vehicle_year` (`vehicle_year`),
KEY `mileage` (`mileage`),
KEY `status` (`status`),
KEY `date_from` (`date_from`),
KEY `date_to` (`date_to`),
KEY `trade_or_private` (`trade_or_private`),
KEY `doors` (`doors`),
KEY `price` (`price`),
KEY `engine_size` (`engine_size`),
KEY `sub_year_id` (`sub_year_id`),
KEY `member_id` (`member_id`),
KEY `date_created` (`date_created`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=136237 ;
l'expliquer :
1 SIMPLE vehicles ref type_id,make_id,status,date_from,date_to,price,mem... type_id 4 const 85695 Using where
1 SIMPLE members index PRIMARY PRIMARY 4 NULL 3 Using where; Using index; Using join buffer
1 SIMPLE vehicles_makes eq_ref PRIMARY PRIMARY 4 tvs.vehicles.make_id 1 Using index
1 SIMPLE vehicles_models eq_ref PRIMARY PRIMARY 4 tvs.vehicles.model_id 1 Using index
1 SIMPLE vehicles_fuel eq_ref PRIMARY PRIMARY 4 tvs.vehicles.fuel_id 1 Using index
1 SIMPLE vehicles_transmissions eq_ref PRIMARY PRIMARY 4 tvs.vehicles.transmission_id 1 Using index
1 SIMPLE vehicles_axles eq_ref PRIMARY PRIMARY 4 tvs.vehicles.axle_id 1 Using index
1 SIMPLE vehicles_sub_years eq_ref PRIMARY PRIMARY 4 tvs.vehicles.sub_year_id 1 Using index
1 SIMPLE vehicles_categories eq_ref PRIMARY PRIMARY 4 tvs.vehicles.category_id 1 Using index
Améliorer la clause d'où
Votre explique montre que MySQL n'utilise qu'un index (type_id
) Pour sélectionner les lignes correspondant à la clause WHERE
, même si vous avez plusieurs critères de la clause.
Pour pouvoir utiliser un index pour tous les critères de la clause où la clause WHERE et réduire la taille du résultat défini le plus rapidement possible, ajoutez un index multi-colonnes sur les colonnes suivantes sur la table des véhicules:
(status, date_from, date_to, type_id, price)
Les colonnes doivent être en ordre de la plus haute cardinalité au moins.
Par exemple, vehicles.date_from
est susceptible d'avoir plus de valeurs distinctes que status
, alors mettez le date_from
colonne avant status
, comme ceci:
(date_from, date_to, price, type_id, status)
Cela devrait réduire les lignes retournées dans la première partie de l'exécution de la requête et doit être démontrée avec un nombre de rangées inférieur sur la première ligne du résultat expliqué.
Vous remarquerez également que MySQL utilisera l'indice multi-colonnes pour le résultat expliqué. Si, par hasard, cela ne signifie pas, vous devez indiquer ou forcer l'index multi-colonnes.
Suppression des jointures inutiles
Il n'apparaît pas que vous utilisez des champs dans l'une des tables jointes, alors retirez les jointures. Cela supprimera tous les travaux supplémentaires de la requête et vous remettra à un seul plan d'exécution simple (une ligne dans le résultat expliqué).
Chaque table jointe provoque une recherche supplémentaire par ligne du jeu de résultats. Donc, si la clause d'où sélectionne 5 000 rangées des véhicules, car vous disposez de 8 jointures aux véhicules, vous aurez 5 000 * 8 = 40 000 recherches. C'est beaucoup à poser à votre serveur de base de données.
Au lieu d'un calcul coûteux de distance précise pour Tout des lignes utilisez une boîte de sélection et calculez la distance exacte uniquement pour les lignes à l'intérieur de la boîte.
L'exemple le plus simple possible consiste à calculer la longitude min/maximum et la latitude qui vous intéresse et l'ajoutez à WHERE
clause. De cette façon, la distance ne sera calculée que pour un sous-ensemble de lignes.
WHERE
vehicles.gps_lat > min_lat ANDd vehicles.gps_lat < max_lat AND
vehicles.gps_lon > min_lon AND vehicles.gps_lon < max_lon
Pour plus de solutions complexes, voir:
Pour être un peu plus spécifique que @Randy of Indexes, je pense que son intention était d'avoir un index composé pour profiter de votre critique de critique ... Un indice construit sur un minimum de ...
( status, type_id, date_from )
mais pourrait être étendu à inclure la date_to et le prix aussi, mais je ne sais pas combien l'indice à ce niveau granulaire pourrait réellement aider
( status, type_id, date_from, date_to, price )
édition par commentaires
Vous ne devriez pas avoir besoin de tous ces index individuels ... Oui, la clé primaire en soi. Toutefois, pour les autres, vous devez avoir des index composés en fonction de vos critères de requête courants et de retirer les autres ... Le moteur pourrait être confondu sur lequel pourrait être mieux adapté à la requête. Si vous savez que vous recherchez toujours un certain statut, tapez et date (en supposant des recherches de véhicule), faites-le comme un indice. Si la requête recherche de telles informations, mais aussi des prix dans ces critères, il sera déjà très proche des rares enregistrements indexés qui se qualifient et volent à travers le prix, à titre de critère supplémentaire.
Si vous proposez une interrogation comme une seule transmission automatique du manuel VS indépendamment de l'année/de la marque, alors oui, cela pourrait être un indice de son propre. Toutefois, si vous auriez généralement des critères "communs", cliquez sur le suivant en tant que secondaire pouvant être utilisé dans la requête. Ex: Si vous recherchez des transmissions manuelles de 2 portes VS 4-Portes, avez votre index sur (transmission_id, catégorie_id).
Encore une fois, vous voulez que tout ce qui aidera à réduire le domaine des critères basés sur une condition "minimale". Si vous cliquez sur une colonne supplémentaire à l'indice qui pourrait être appliqué "communément", cela ne devrait qu'aider la performance.
Pour clarifier cela comme une réponse: Si vous n'avez pas déjà ces index, vous devriez envisager d'ajouter
avez-vous également des index sur ceux-ci:
vehicles.status
vehicles.date_from
vehicles.date_to
vehicles.type_id
vehicles.price