2009-10-02 15 views
0

Je voudrais savoir comment optimiser le SQL suivant pour permettre à mon serveur de se charger plus rapidement et de consommer moins? Je dois calculer la distance de rayon pour un code postal américain pour obtenir le résultat, comme 50 milles d'un code postal particulier (en utilisant la latitude et la longitude pour calculer) et pour obtenir combien d'autres données (par ex.) de ma base de données. Une fois le résultat obtenu (par exemple 350 lignes de codes postaux différents dans un rayon de 50 miles à partir d'un code postal particulier), je dois les transmettre à une autre requête pour compter le nombre total de lignes et l'afficher en un moi de lire. Voici un exemple de ma requête:Comment optimiser mon SQL dans le serveur?

SELECT count(*) 
FROM 
(SELECT b.ID, ROUND((acos(sin(3.142/180*32.91336) * sin(3.142/180*z.latitude) + cos(3.142/180*32.91336) * cos(3.142/180*z.latitude) * cos((3.142/180*z.longitude) - (3.142/180*-85.93836))) * 3959),2) AS distance 
    FROM zipcode2business.accountants b LEFT JOIN zipcodeworld.storelocator_us z ON b.ZIPCODE = z.ZIP_CODE 
    WHERE z.latitude != 32.91336 AND z.longitude != -85.93836 
    AND b.STATE='AL' 
    HAVING distance between 0 AND 50) 
as total; 

Espérons que je n'ai pas fait mal, il affiche un résultat correct (350 lignes), mais je besoin d'un moyen optimisé pour il fonctionne parce que ce SQL m'a donné une utilisation élevée du processeur charger. Quand je n'EXPLIQUER pour cette requête, il affichage suivant:

+----+-------------+-------+--------+------------------+---------+---------+----------------------------+------+------------------------------+ 
| id | select_type | table | type | possible_keys | key  | key_len | ref      | rows | Extra      | 
+----+-------------+-------+--------+------------------+---------+---------+----------------------------+------+------------------------------+ 
| 1 | PRIMARY  | NULL | NULL | NULL    | NULL | NULL |  NULL    | NULL | Select tables optimized away | 
| 2 | DERIVED  | b  | ref | ZIPCODE,STATE | STATE | 4  |       | 3900 | Using where     | 
| 2 | DERIVED  | z  | eq_ref | PRIMARY,LAT_LONG | PRIMARY | 9  | zipcode2business.b.ZIPCODE | 1 | Using where     | 
+----+-------------+-------+--------+------------------+---------+---------+----------------------------+------+------------------------------+ 
3 rows in set (0.20 sec) 

maintenant, d'explication ci-dessus, la « Sélectionner les tables optimisés loin » dans EXTRA est une bonne chose? S'il vous plaît veuillez me montrer une optimisation SQL le plus parfait pour faire cette requête.

Répondre

0

Avez-vous besoin de faire tous ces calculs sur le serveur sql? J'essaie généralement d'utiliser SQL pour le CRUD de base avec les données, alors tous les autres calculs sont faits en dehors de SQL. Vous pouvez essayer d'extraire les données sur lesquelles vous basez vos calculs, puis effectuer le calcul réel avec tout ce qui récupère les données.

1

Le SQL semble bonne fin, la majeure partie du temps CPU doit être passé à faire des maths ... Il y a deux possibilités pour l'optimisation

  • simplifier les formules
  • les lignes de filtre-tôt (» élaguer "), sur la base d'un calcul encore plus simple

Je n'ai pas le temps pour l'instant pour plus de détails, mais ici l'idée générale:
Il est à environ la distance de l'emplacement de référence ZipCode et des autres emplacements, avec un calcul bon marché (CPU-sage), et de faire seulement le calcul complet (avec une meilleure formule que celle de la requête originale), pour les emplacements qui sont inférieurs à 50 miles (+ un petit extra, pour tenir compte d'une éventuelle sous-estimation).

estimation de la distance et la taille
Nous Calculons, une fois, la distance expessed en miles, ce qui correspond à un degré de latitude et à un degré de longitude, de l'emplacement ZipCode de référence; appelez ces MpDLat et MpDLong. Il est possible que nous calculions la valeur fractionnaire du degré correspondant à notre rayon cible à partir de l'emplacement de référence; appelez ces Dp50Lat et Dp50Long. Travailler ensuite avec la [valeur absolue de] la différence entre les latitudes et entre les longitudes, par rapport à l'emplacement de référence, et filtrer les emplacements pour lesquels cette distance dans une direction (lat ou long) dépasse notre limite. c'est à dire.quelque chose comme

WHERE .... (some other condidtions....) 
    AND (abs(z.latitude - 32.91336) * MpDLat) < 50 
    AND (abs(z.longitude + 85.93836) * MpDLong) < 50 
--or, if we got by the Dp50 values 
WHERE .... (some other condidtions....) 
    AND (abs(z.latitude - 32.91336) < Dp50Lat 
    AND (abs(z.longitude + 85.93836) < Dp50Long 

Calcul de la distance (car il n'y endroits pas facilement filtrés)
En fonction du niveau de précision requis, il peut être acceptable de rester avec les facteurs mpd (je devine des erreurs de moins d'un mile ou plus, pour des distances de l'ordre de 50 miles, dans les Etats-Unis continentaux). Alors les distances seraient calculées comme: Sqrt ((z.latitude - 32.91336)^2 + (z.longitude + 85.93836)^2 ou, si nous sommes seulement intéressés à filtrer ceux-ci sans besoin de la distance en soi, nous peuvent travailler hors des carrés, ce ... OU (z.latitude - 32,91336)^2 + (+ z.longitude 85,93836)^2 < 2500-2509 est 50^2

Je devine que ce type d'approximation est acceptable, car des erreurs beaucoup plus grandes sont faites compte tenu du fait que la distance par voie de routes (qui est probablement celle que l'on souhaite éventuellement) correspond rarement à celle des «mouches à vol d'oiseau» ;-) Je peux calculer avec précision pire cas de perte de précision (mais encore une fois, pas le temps pour ça maintenant ...)

Si la distance exacte est nécessaire, nous utilisons une formule légèrement meilleure que l'original, celle-ci semble directement dérivée de la loi sphérique du cosinus. Nous pouvons probablement faire mieux.

Variations sur les
ci-dessus Les idées discutées ci-dessus peuvent être mises en œuvre dans divers mode, par exemple avec l'utilisation de tables temporaires SQL, ou diverses constructions pour la requête (s), etc.

0

vous peut sélectionner le calcul de la distance dans une table temporaire et supprimer le HAVING de votre SQL, puis faire un 2ème SELECT SELECT OLE dist < = 50

cela permet d'économiser de l'espace mémoire et possible échanger des segments de disque temporaires pour un grand nombre d'enregistrements dans votre table de base

Questions connexes