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?
Utilisez les extensions spatiales de MySQL avec GIS.
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"
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.
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.
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.
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:
DOUBLE
.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:
POINT
, l'ordre des arguments pour stocker les coordonnées doit être POINT(latitude, longitude)
.ST_Distance
) et déterminer si un point est contenu dans une autre zone ( ST_Contains
).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.
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.
Pas besoin d’aller loin, selon Google Maps, le meilleur est FLOAT (10,6) pour les lat et lng.
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.
Dans une perspective complètement différente et plus simple:
VARCHAR
), par exemple: " -0000.0000001, -0000.000000000000001 " (35 longueurs et si un nombre a plus de 7 chiffres décimaux, puis il est arrondi);google.maps.geometry.poly.containsLocation(latLng, bermudaTrianglePolygon))
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.
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:
J'ai parlé de tout cela dans un article de blog récent: http://blog.webfoot.com/2013/03/12/optimizing-map-tile-generation/
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)
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
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é.
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.
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
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
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)
Les latitudes varient de -90 à +90 (degrés), donc DECIMAL (10, 8) est acceptable pour cela
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