8
votes

Sélectionnant efficacement l'enregistrement le plus proche (distance) d'une base de données

J'ai une base de données avec une salle de 40k et de grandir en ce moment.

supposer que je suis le point rouge

facile
Je veux pouvoir récupérer l'enregistrement le plus proche aussi rapidement que possible.

Cependant, la distance aussi l'élément suivant pourrait être n'importe quoi. Et il pourrait également y avoir des matchs 0-N. Mais dois-je charger tous les 40000 résultats quand je cherche juste 1? moins évident

Comment puis-je trier les enregistrements par distance? Devrait-il être fait dans MySQL ou PHP? Ce calcul se produit à presque toutes les demandes, par utilisateur, par page, la solution doit donc être rapide.

Modifier Merci pour les réponses rapides et prometteuses, je devrai examiner ces ressources et acceptera / commenter des réponses dans quelques jours.


3 commentaires

Avez-vous essayé l'inclusion de la distance avec le lieu (en utilisant une colonne calculée) dans la requête et voyez combien de temps cela va?


Titulaire @sam J'ai exécuté des requêtes à l'aide du calcul de Pythagoran simple, pour vérifier les sites à proximité d'une intersection et l'exécution de script est de 1 à 2 secondes plus lente que les sites attribués à une intersection. (Pour un ordinateur, je sens que c'est une longue période)


OK bien. Je vérifiais juste que l'évidence avait été faite en premier et que la solution simple n'était pas appropriée :)


4 Réponses :


3
votes

La solution la plus simple consiste à calculer de simples calculer la distance pour chaque enregistrement et trier par cette valeur. Le problème est: c'est très cher et vous ne pouvez pas utiliser un index pour cette forte>. Vous pouvez réduire les coûts en examinant uniquement un sous-ensemble de vos dossiers, peut-être limiter par une boîte de sélection comme des affiches ici suggèrent ici.

Si vous voulez une solution claire et rapide, jetez un coup d'œil à la Extensions spatiales de MySQL em>. Celles-ci sont faites exactement pour ce que vous voulez faire. Ces supports: p>

  • Un nouveau type de colonne 'Point' Li>
  • Un type d'index spécial optimisé pour les requêtes de distance li>
  • Un opérateur de distance. LI> ul>

    Ce HOWTO fournit quelques exemples: P>

    CREATE TABLE address (
      address CHAR(80) NOT NULL,
      address_loc POINT NOT NULL,
      PRIMARY KEY(address),
      SPATIAL KEY(address_loc)
    );
    CREATE TABLE cab (
      cab_id INT AUTO_INCREMENT NOT NULL,
      cab_driver CHAR(80) NOT NULL,
      cab_loc POINT NOT NULL,
      PRIMARY KEY(cab_id),
      SPATIAL KEY(cab_loc)
    );
    
    SELECT
      c.cab_driver,
      ROUND(GLength(LineStringFromWKB(LineString(AsBinary(c.cab_loc),
                                                 AsBinary(a.address_loc)))))
        AS distance
    FROM cab c, address a
    WHERE a.address = 'Foobar street 110'
    ORDER BY distance ASC LIMIT 1;
    


1 commentaires

Notez qu'il existe un indice spatial spécial comme contre l'indice de DB habituel pouvant être exploité



8
votes

Ce problème est couvert dans cette présentation scribd (Théory + Math Formulas + MySQL): Geo Distance avec MySQL

J'espère que cela couvre tout ce dont vous avez besoin


0 commentaires

1
votes

Créer une "zone de liaison" à utiliser dans une clause WHERE dans votre requête SQL comme décrit dans cette Article sur type mobile (avec des exemples de code PHP), inclure la formule Haversine dans votre requête pour calculer les distances réelles et commander le résultat par distance ASC. Le lieu le plus proche sera alors le premier retour de la série de résultats.

C'est la boîte de sélection qui aide vos performances, car cela signifie que vous ne faites que le calcul de la distance coûteux sur un petit sous-ensemble de vos données

Si la requête initiale ne renvoie aucun enregistrement, élargissez la zone de sélection et exécutez la requête à nouveau jusqu'à ce que vous obteniez une réponse.


0 commentaires

1
votes

Il n'y a pas de moyen efficace de trouver la distance sauf par essai et par erreur. C'est-à-dire à l'aide de MySQL, vous ne pouvez pas classer les enregistrements par distance de la cible, puis sélectionnez le sommet. Le meilleur moyen est de choisir une distance que vous pensez que l'enregistrement le plus proche sera à l'intérieur. Trop gros un nombre et vous obtiendrez trop de disques, trop petit un nombre et vous n'en tirerez pas. Disons que vous choisissez 40 unités.

WHERE xcoord BETWEEN n - 40 AND n + 40 AND ycoord BETWEEN n - 40 AND n + 40


0 commentaires