web-dev-qa-db-fra.com

Quel est le type de données idéal à utiliser pour stocker latitude/longitude dans une base de données MySQL?

Sachant que je vais effectuer des calculs sur des paires lat/long, quel type de données est le plus approprié pour une base de données MySQL?

389
Codebeef

Utilisez les extensions spatiales de MySQL avec GIS.

149
Kirk Strauser

Google fournit une solution PHP/MySQL de bout en bout pour un exemple d'application "Store Locator" avec Google Maps. Dans cet exemple, ils stockent les valeurs lat/lng sous la forme "Float" avec une longueur de "10,6"

http://code.google.com/apis/maps/articles/phpsqlsearch.html

142
Ted Avery

Cela dépend essentiellement de la précision dont vous avez besoin pour vos emplacements. En utilisant DOUBLE, vous aurez une précision de 3,5 nm. DECIMAL (8,6)/(9,6) descend à 16cm. FLOTTEUR est 1,7m ...

Ce tableau très intéressant a une liste plus complète: http://mysql.rjweb.org/doc.php/latlng :

Datatype               Bytes            Resolution

Deg*100 (SMALLINT)     4      1570 m    1.0 mi  Cities
DECIMAL(4,2)/(5,2)     5      1570 m    1.0 mi  Cities
SMALLINT scaled        4       682 m    0.4 mi  Cities
Deg*10000 (MEDIUMINT)  6        16 m     52 ft  Houses/Businesses
DECIMAL(6,4)/(7,4)     7        16 m     52 ft  Houses/Businesses
MEDIUMINT scaled       6       2.7 m    8.8 ft
FLOAT                  8       1.7 m    5.6 ft
DECIMAL(8,6)/(9,6)     9        16cm    1/2 ft  Friends in a mall
Deg*10000000 (INT)     8        16mm    5/8 in  Marbles
DOUBLE                16       3.5nm     ...    Fleas on a dog

J'espère que cela t'aides.

110
Simon

Les extensions spatiales de MySQL sont la meilleure option car vous disposez de la liste complète des opérateurs et des index spatiaux. Un index spatial vous permettra d'effectuer très rapidement des calculs basés sur la distance. N'oubliez pas qu'à partir de la version 6.0, l'extension spatiale est toujours incomplète. Je ne dénigre pas MySQL Spatial, je vous tiens au courant des pièges avant de vous lancer trop loin dans ce processus.

Si vous traitez strictement avec des points et uniquement avec la fonction DISTANCE, c'est très bien. Si vous devez effectuer des calculs avec des polygones, des lignes ou des points tamponnés, les opérateurs spatiaux ne fournissent pas les résultats exacts à moins que vous n'utilisiez l'opérateur "relier". Voir l'avertissement en haut de 21.5.6 . Les relations telles que contient, dans, ou intersections utilisent le MBR, et non la forme géométrique exacte (c’est-à-dire qu’une Ellipse est traitée comme un rectangle).

De plus, les distances dans MySQL Spatial sont dans les mêmes unités que votre première géométrie. Cela signifie que si vous utilisez des degrés décimaux, vos mesures de distance sont exprimées en degrés décimaux. Cela rendra très difficile l’obtention de résultats exacts à mesure que vous obtiendrez de l’équateur. 

74
James Schek

Quand j'ai fait cela pour une base de données de navigation construite à partir d'ARINC424, j'ai fait pas mal de tests et, en revenant sur le code, j'ai utilisé un DECIMAL (18,12) (en réalité un NUMERIC (18,12) parce que c'était Firebird).

Les flotteurs et les doubles ne sont pas aussi précis et peuvent entraîner des erreurs d'arrondi, ce qui peut être une très mauvaise chose. Je ne me souviens pas si j'ai trouvé des données réelles qui posaient problème, mais je suis à peu près certain que l'incapacité de stocker avec précision dans un flottant ou un double pourrait poser problème.

Le fait est que lorsque nous utilisons des degrés ou des radians, nous connaissons la plage des valeurs - et la partie fractionnaire nécessite le plus grand nombre de chiffres.

Les Les extensions spatiales MySQL sont une bonne alternative car elles suivent Le modèle de géométrie OpenGIS . Je ne les ai pas utilisées car je devais garder ma base de données portable.

69
Richard Harrison

Cela dépend de la précision dont vous avez besoin.

Datatype           Bytes       resolution
------------------ -----  --------------------------------
Deg*100 (SMALLINT)     4  1570 m    1.0 mi  Cities
DECIMAL(4,2)/(5,2)     5  1570 m    1.0 mi  Cities
SMALLINT scaled        4   682 m    0.4 mi  Cities
Deg*10000 (MEDIUMINT)  6    16 m     52 ft  Houses/Businesses
DECIMAL(6,4)/(7,4)     7    16 m     52 ft  Houses/Businesses
MEDIUMINT scaled       6   2.7 m    8.8 ft
FLOAT                  8   1.7 m    5.6 ft
DECIMAL(8,6)/(9,6)     9    16cm    1/2 ft  Friends in a mall
Deg*10000000 (INT)     8    16mm    5/8 in  Marbles
DOUBLE                16   3.5nm     ...    Fleas on a dog

De: http://mysql.rjweb.org/doc.php/latlng

Pour résumer:

  • L'option disponible la plus précise est DOUBLE.
  • Le type vu le plus couramment utilisé est DECIMAL(8,6)/(9,6).

À partir de MySQL 5.7 , pensez à utiliser Types de données spatiales (SDT), en particulier POINT pour stocker une seule coordonnée. Avant la version 5.7, SDT ne prend pas en charge les index (à l'exception de 5.6 lorsque le type de table est MyISAM).

Remarque:

  • Lorsque vous utilisez la classe POINT, l'ordre des arguments pour stocker les coordonnées doit être POINT(latitude, longitude).
  • Il existe une syntaxe spéciale pour créer un index spatial .
  • Le principal avantage de l’utilisation de SDT est que vous avez accès à Fonctions d’analyses spatiales , par exemple. calculer la distance entre deux points ( ST_Distance ) et déterminer si un point est contenu dans une autre zone ( ST_Contains ).
36
Gajus

Basé sur cet article de wiki http://en.wikipedia.org/wiki/Decimal_degrees#Accuracy Le type de données approprié dans MySQL est Decimal (9,6) pour stocker la longitude et la latitude dans champs séparés.

32
saeed khalafinejad

Utilisez DECIMAL(8,6) pour la latitude (90 à -90 degrés) et DECIMAL(9,6) pour la longitude (180 à -180 degrés). 6 décimales convient à la plupart des applications. Les deux doivent être "signés" pour permettre les valeurs négatives.

19
Alex Holsgrove

Pas besoin d’aller loin, selon Google Maps, le meilleur est FLOAT (10,6) pour les lat et lng.

13
Mariano Peinador

Nous stockons latitude/longitude X 1 000 000 dans notre base de données Oracle sous le nom NUMBERS pour éviter les erreurs d'arrondi par des doubles.

Étant donné que la latitude/longitude jusqu'à la 6ème décimale était une précision de 10 cm, c'était tout ce dont nous avions besoin. De nombreuses autres bases de données stockent également la latitude/longitude jusqu'à la 6ème décimale.

7
user18443

Dans une perspective complètement différente et plus simple:

  • si vous comptez sur Google pour afficher vos cartes, vos marqueurs, vos polygones, peu importe, laissez les calculs se faire par Google!
  • vous économisez des ressources sur votre serveur et vous stockez simplement la latitude et la longitude en une seule chaîne (VARCHAR), par exemple: " -0000.0000001, -0000.000000000000001 " (35 longueurs et si un nombre a plus de 7 chiffres décimaux, puis il est arrondi);
  • si Google renvoie plus de 7 chiffres décimaux par nombre, vous pouvez néanmoins conserver ces données dans votre chaîne, au cas où vous souhaiteriez détecter des fuites ou des microbes dans le futur ;
  • vous pouvez utiliser leur matrice distance ou leur bibliothèque géométrie pour calculer des distances ou détecter des points dans certaines zones avec des appels aussi simples que ceci: google.maps.geometry.poly.containsLocation(latLng, bermudaTrianglePolygon))
  • il existe de nombreuses API "côté serveur" que vous pouvez utiliser (dans Python , Ruby on Rails , PHP , CodeIgniter , Laravel , Yii , Zend Framework , etc.) qui utilisent l'API Google Maps.

De cette façon, vous n'avez pas à vous soucier de l'indexation des numéros ni de tous les autres problèmes associés aux types de données susceptibles de gâcher vos coordonnées.

6
Armfoot

Bien que cela ne soit pas optimal pour toutes les opérations, si vous créez des tuiles de carte ou travaillez avec un grand nombre de marqueurs (points) avec une seule projection (par exemple, Mercator, comme Google Maps et de nombreux autres frameworks de cartes glissantes attendus), j'ai trouvé ce que J'appelle "Vast Coordinate System" pour être vraiment très pratique. Fondamentalement, vous stockez les coordonnées en pixels x et y de façon zoomée - j'utilise le niveau de zoom 23. Cela présente plusieurs avantages:

  • Vous effectuez la transformation coûteuse lat/lng en pixel de mercator une fois au lieu de chaque fois que vous manipulez le point
  • Obtenir la coordonnée de la tuile à partir d'un enregistrement avec un niveau de zoom prend un décalage à droite.
  • L'obtention de la coordonnée en pixels d'un enregistrement prend un décalage à droite et un ET au niveau du bit.
  • Les changements sont si légers qu’il est pratique de les utiliser en SQL, ce qui signifie que vous pouvez effectuer une commande DISTINCT pour renvoyer un seul enregistrement par emplacement de pixel, ce qui réduira le nombre d’enregistrements renvoyés par le backend, ce qui signifie moins de traitement sur le disque. l'extrémité avant. 

J'ai parlé de tout cela dans un article de blog récent: http://blog.webfoot.com/2013/03/12/optimizing-map-tile-generation/

4

en fonction de votre application, je suggère d'utiliser FLOAT (9,6)

les clés spatiales vous donneront plus de fonctionnalités, mais dans les tests de production, les flottants sont beaucoup plus rapides que les clés spatiales. (0,01 VS 0,001 en AVG)

4
Torben Brodt

MySQL utilise double pour tous les flottants ... Donc utilisez le type double. L'utilisation de float conduira à des valeurs arrondies imprévisibles dans la plupart des situations

3
mlinuxgada

Je suis très surpris par certaines réponses/commentaires.

Pourquoi diable voudrait-on volontairement "pré-diminuer" la précision, puis effectuer des calculs plus tard? Cela semble finalement stupide.

Si la source a une précision de 64 bits, il serait certainement idiot de fixer volontairement l'échelle à, par exemple. 6 décimales et limitez la précision à un maximum de 9 chiffres significatifs (ce qui se produit avec le format décimal 9.6 couramment proposé).

Naturellement, on stocke les données avec la précision du matériel source. La seule raison de diminuer la précision serait un espace de stockage limité.

  • Stocker les chiffres source avec une précision originale
  • Stocker les chiffres calculés à partir de la source dans la précision du calcul (par exemple, si le code d'application utilise des doublons, stocke les résultats sous forme de doublons)

Le format décimal 9.6 provoque un phénomène d’accrochage à la grille. Cela devrait être la toute dernière étape, si cela doit arriver.

Je n'inviterais pas les erreurs accumulées dans mon nid.

3
Stormwind

Les fonctions spatiales dans PostGIS sont beaucoup plus fonctionnelles (c'est-à-dire non limitées aux opérations BBOX) que celles des fonctions spatiales MySQL. Check it out: texte du lien

3
Dylan

TL; DR

Utilisez FLOAT (8,5) si vous ne travaillez pas dans la NASA/militaire et ne fabriquez pas de systèmes de navigation aérienne.


Pour répondre pleinement à votre question, vous devez prendre en compte plusieurs éléments:

Format

  • degrés minutes secondes: 40 ° 26 ′ 46 ″ N 79 ° 58 ′ 56 ″ W
  • degrés en minutes décimales: 40 ° 26,767 ′ N 79 ° 58,933 ′ W
  • degrés décimaux 1: 40,446 ° N 79,982 ° W
  • degrés décimaux 2: -32.60875, 21.27812
  • Un autre format fait maison? Personne ne vous interdit de créer votre propre système de coordonnées centré sur votre maison et de le stocker sous forme de cap et de distance de votre domicile. Cela peut avoir un sens pour certains problèmes spécifiques sur lesquels vous travaillez.

La première partie de la réponse serait donc: vous pouvez stocker les coordonnées dans le format utilisé par votre application pour éviter les conversions constantes et simplifier les requêtes SQL.

Très probablement, vous utilisez Google Maps ou OSM pour afficher vos données, et les cartes GMaps utilisent le format "degrés décimaux 2". Il sera donc plus facile de stocker les coordonnées dans le même format.

Précision

Ensuite, vous souhaitez définir la précision dont vous avez besoin. Bien sûr, vous pouvez enregistrer des coordonnées comme "-32.608697550570334,21.278081997935146", mais vous êtes-vous déjà soucié des millimètres lorsque vous naviguez jusqu'au point? Si vous ne travaillez pas dans la NASA et que vous ne faites pas de trajectoires de satellites, de fusées ou d'avions, vous devriez vous en sortir avec une précision de plusieurs mètres.

Le format couramment utilisé est 5 chiffres après les points, ce qui vous donne une précision de 50 cm.

Exemple: il existe une distance de 1 cm entre X, 21.2780818 et X, 21.2780819. Ainsi, 7 chiffres après le point vous donnent une précision de 1/2cm et 5 chiffres après le point vous donneront une précision de 1/2 mètres (car la distance minimale entre des points distincts est de 1 m, une erreur d'arrondi ne peut donc pas en dépasser la moitié). Pour la plupart des objectifs civils, cela devrait suffire.

degrés décimales minutes (40 ° 26.767 ′ N 79 ° 58.933 ′ W) vous donne exactement la même précision que 5 chiffres après le point 

Stockage peu encombrant

Si vous avez sélectionné le format décimal, votre coordonnée est une paire (-32.60875, 21.27812). De toute évidence, 2 x (1 bit pour le signe, 2 chiffres pour les degrés et 5 chiffres pour l'exposant) suffiront. 

Je voudrais donc ici soutenir Alix Axel à partir de commentaires disant que la suggestion de Google de le stocker dans FLOAT (10,6) est vraiment extra, car vous n'avez pas besoin de 4 chiffres pour la partie principale (puisque le signe est séparé et la latitude est limitée à 90 et la longitude est limitée à 180). Vous pouvez facilement utiliser FLOAT (8,5) pour une précision de 1/2m ou FLOAT (9,6) pour une précision de 50/2cm. Ou vous pouvez même stocker lat et long dans des types séparés, parce que FLOAT (7,5) est suffisant pour lat. Voir MySQL float types référence . N'importe lequel d'entre eux ressemblera à FLOAT normal et sera égal à 4 octets de toute façon.

Habituellement, l’espace n’est plus un problème de nos jours, mais si vous voulez vraiment optimiser le stockage pour une raison quelconque (Avertissement: ne faites pas de pré-optimisation), vous pouvez compresser lat (pas plus de 91 000 valeurs + signe) + long (non plus de 181 000 valeurs + signe) à 21 bits, soit beaucoup moins que 2xFLOAT (8 octets == 64 bits)

2
The Godfather
  1. Les latitudes varient de -90 à +90 (degrés), donc DECIMAL (10, 8) est acceptable pour cela

  2. les longitudes vont de -180 à +180 (degrés) donc vous avez besoin de DECIMAL (11, 8).

Remarque: le premier nombre correspond au nombre total de chiffres enregistrés et le second au nombre suivant le point décimal.

En bref: lat DECIMAL(10, 8) NOT NULL, lng DECIMAL(11, 8) NOT NULL

0
mahfuz