Sachant que je vais effectuer des calculs sur des paires lat / longues, quel type de données convient le mieux à une utilisation avec une base de données MySQL?
Sachant que je vais effectuer des calculs sur des paires lat / longues, quel type de données convient le mieux à une utilisation avec une base de données MySQL?
Réponses:
Utilisez les extensions spatiales de MySQL avec SIG.
Google fournit une solution de début à la fin PHP / MySQL pour un exemple d'application "Store Locator" avec Google Maps. Dans cet exemple, ils stockent les valeurs lat / lng comme "Float" avec une longueur de "10,6"
FLOAT(10,6)
laisse 4 chiffres pour la partie entière des coordonnées. Et non, le signe ne compte pas - cela vient de l'attribut (non) signé.
Double
de données pour Laravel
Fondamentalement, cela dépend 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 à 16 cm. FLOTTEUR mesure 1,7 m ...
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 avez la liste complète des opérateurs spatiaux et des indices à votre disposition. 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 mets pas fin à MySQL Spatial, je ne fais que vous informer des pièges avant d'aller trop loin.
Si vous traitez strictement des points et seulement 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 des résultats exacts que si vous utilisez l'opérateur "relier". Voir l'avertissement en haut de 21.5.6 . Les relations telles que contient, à l'intérieur ou intersectent utilisent le MBR, pas 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 en degrés décimaux. Cela rendra très difficile l'obtention de résultats exacts lorsque vous obtiendrez furthur 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 regardant le code, j'ai utilisé un DECIMAL (18,12) (en fait 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é de vraies données qui avaient des problèmes - mais je suis assez certain que l'incapacité à stocker avec précision dans un flotteur ou un double pourrait causer des problèmes
Le fait est que lorsque vous utilisez des degrés ou des radians, nous connaissons la plage des valeurs - et la partie fractionnaire a besoin du plus de chiffres.
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és parce que je devais garder ma base de données portable.
a*b
n'était pas égal b*a
(pour certaines valeurs). Il y avait de nombreux exemples un peu comme: 2+2 = 3.9999
. La norme a nettoyé beaucoup de gâchis et a été «rapidement» adoptée par pratiquement chaque matériel et logiciel. Cette discussion est donc valable, non seulement depuis 2008, mais depuis un tiers de siècle.
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)
.Depuis MySQL 5.7 , envisagez d'utiliser des types de données spatiales (SDT), spécifiquement POINT
pour stocker une seule coordonnée. Avant 5.7, SDT ne prend pas en charge les index (à l'exception de 5.6 lorsque le type de table est MyISAM).
Remarque:
POINT
classe, l'ordre des arguments pour le stockage des coordonnées doit être POINT(latitude, longitude)
.ST_Distance
) et déterminer si un point est contenu dans une autre zone ( ST_Contains
).CREATE TABLE geom (g GEOMETRY NOT NULL, SPATIAL INDEX(g)) ENGINE=MyISAM;
et l'avertissement sur les limitations SDT, comme James l'a mentionné , votre réponse sera peut-être plus concise et précise pour aider les autres. ..
Basé sur cet article 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 des champs séparés.
À utiliser DECIMAL(8,6)
pour la latitude (90 à -90 degrés) et DECIMAL(9,6)
pour la longitude (180 à -180 degrés). 6 décimales conviennent à la plupart des applications. Les deux doivent être «signés» pour permettre des valeurs négatives.
DECIMAL
Le type est destiné aux calculs financiers où aucun floor/ceil
n'est accepté. Plain FLOAT
surperforme considérablement DECIMAL
.
Pas besoin d'aller loin, selon Google Maps, le meilleur est FLOAT (10,6) pour lat et lng.
lat FLOAT( 10, 6 ) NOT NULL,
lng FLOAT( 10, 6 ) NOT NULL
FLOAT
syntaxe soit obsolète depuis mysql 8.0.17
. Mysql recommande désormais de simplement utiliser FLOAT
sans aucun paramètre de précision dev.mysql.com/doc/refman/8.0/en/numeric-type-overview.html et dev.mysql.com/doc/refman/5.5/en/floating-point- types.html
Nous stockons la latitude / longitude X 1 000 000 dans notre base de données Oracle sous forme de NOMBRES pour éviter les erreurs d'arrondi avec des doubles.
Étant donné que la latitude / longitude à la 6e 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 lat / long à la 6ème décimale.
Dans une perspective complètement différente et plus simple:
VARCHAR
), par exemple: " -0000.0000001, -0000.000000000000001 " (35 de longueur et si un nombre a plus de 7 chiffres décimaux, il est arrondi);google.maps.geometry.poly.containsLocation(latLng, bermudaTrianglePolygon))
De cette façon, vous n'avez pas à vous soucier de l'indexation des nombres et de tous les autres problèmes associés aux types de données qui peuvent gâcher vos coordonnées.
selon votre application, je suggère d'utiliser FLOAT (9,6)
les clés spatiales vous donneront plus de fonctionnalités, mais dans les repères de production, les flotteurs sont beaucoup plus rapides que les clés spatiales. (0,01 VS 0,001 en AVG)
MySQL utilise le double pour tous les flottants ... Utilisez donc le type double. L'utilisation de float entraînera des valeurs arrondies imprévisibles dans la plupart des situations
DOUBLE
. MySQL vous permet de stocker des données sous forme de 4 octets FLOAT
ou de 8 octets DOUBLE
. Il y aura donc probablement une perte de précision lors du stockage d'une expression dans une FLOAT
colonne.
Bien qu'il 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 cadres de cartes glissantes s'attendent), j'ai trouvé ce que J'appelle "Vast Coordinate System" pour être vraiment, vraiment pratique. Fondamentalement, vous stockez les coordonnées de pixels x et y à un certain zoom - j'utilise le niveau de zoom 23. Cela présente plusieurs avantages:
J'ai parlé de tout cela dans un récent article de blog: http://blog.webfoot.com/2013/03/12/optimizing-map-tile-generation/
Je suis très surpris par quelques réponses / commentaires.
Pourquoi diable quelqu'un serait-il disposé à "pré-diminuer" volontairement la précision, puis à effectuer plus tard des calculs sur les pires nombres? Cela semble finalement stupide.
Si la source a une précision de 64 bits, il serait certainement stupide de fixer volontairement l'échelle à, par exemple. 6 décimales et limiter 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 de snap-to-grid. Cela devrait être la toute dernière étape, si cela devait arriver.
Je n'inviterais pas les erreurs accumulées dans mon nid.
TL; DR
Utilisez FLOAT (8,5) si vous ne travaillez pas dans la NASA / militaire et ne fabriquez pas de systèmes navi pour avions.
Pour répondre pleinement à votre question, vous devez considérer plusieurs choses:
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 des conversions constantes d'avant en arrière et simplifier les requêtes SQL.
Vous utilisez probablement Google Maps ou OSM pour afficher vos données, et GMaps utilise le format "degrés décimaux 2". Il sera donc plus facile de stocker des 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 stocker des coordonnées comme "-32.608697550570334,21.278081997935146", mais vous êtes-vous déjà soucié des millimètres lors de la navigation jusqu'au point? Si vous ne travaillez pas à la NASA et ne faites pas de trajectoires de satellites ou de fusées ou d'avions, vous devriez être bien avec une précision de plusieurs mètres.
Le format couramment utilisé est de 5 chiffres après les points, ce qui vous donne une précision de 50 cm.
Exemple : il y a une distance de 1 cm entre X, 21.278081 8 et X, 21.278081 9 . Ainsi, 7 chiffres après le point vous donnent une précision de 1/2 cm et 5 chiffres après le point vous donneront une précision de 1/2 mètre (car la distance minimale entre les points distincts est de 1 m, donc l'erreur d'arrondi ne peut pas être supérieure à la moitié). Pour la plupart des fins civiles, cela devrait suffire.
le format des degrés décimaux minutes (40 ° 26,767 ′ N 79 ° 58,933 ′ O) 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). Évidemment, 2 x (1 bit pour le signe, 2 chiffres pour les degrés et 5 chiffres pour l'exposant) suffiront.
Donc, ici, je voudrais soutenir Alix Axel dans les commentaires disant que la suggestion de Google de le stocker dans FLOAT (10,6) est vraiment supplémentaire, car vous n'avez pas besoin de 4 chiffres pour la partie principale (car 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, car FLOAT (7,5) est suffisant pour lat. Voir Référence des types de flotteurs MySQL . Chacun d'eux sera comme FLOAT normal et égal à 4 octets de toute façon.
Habituellement, l'espace n'est pas 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, ce qui est nettement inférieur à 2xFLOAT (8 octets == 64 bits)
Les fonctions spatiales de PostGIS sont beaucoup plus fonctionnelles (c'est-à-dire non limitées aux opérations BBOX) que celles des fonctions spatiales MySQL. Découvrez-le: texte du lien
Les latitudes varient de -90 à +90 (degrés), donc DECIMAL (10, 8) est correct pour cela
les longitudes varient de -180 à +180 (degrés), vous avez donc besoin de DECIMAL (11, 8).
Remarque: Le premier nombre est le nombre total de chiffres stockés et le second est le nombre après la virgule décimale.
En bref: lat DECIMAL(10, 8) NOT NULL, lng DECIMAL(11, 8) NOT NULL
Je vous suggère d'utiliser le type de données Float pour SQL Server.
Les calculs lat longs nécessitent une précision, utilisez donc un type de type décimal et augmentez la précision d'au moins 2 par rapport au nombre que vous stockerez afin d'effectuer des calculs mathématiques. Je ne connais pas les types de données my sql mais dans SQL Server, les gens utilisent souvent float ou real au lieu de decimal et ont des ennuis car ce sont des nombres estimés et non réels. Assurez-vous donc simplement que le type de données que vous utilisez est un vrai type décimal et non un type décimal flottant et que tout devrait bien se passer.
A FLOAT
devrait vous donner toute la précision dont vous avez besoin et être meilleur pour les fonctions de comparaison que de stocker chaque coordonnée sous forme de chaîne ou similaire.
Si votre version de MySQL est antérieure à 5.0.3, vous devrez peut-être tenir compte de certaines erreurs de comparaison en virgule flottante .
Avant MySQL 5.0.3, les colonnes DECIMAL stockent les valeurs avec une précision exacte car elles sont représentées sous forme de chaînes, mais les calculs sur les valeurs DECIMAL sont effectués à l'aide d'opérations à virgule flottante. Depuis la version 5.0.3, MySQL effectue des opérations DECIMAL avec une précision de 64 chiffres décimaux, ce qui devrait résoudre les problèmes d'imprécision les plus courants en ce qui concerne les colonnes DECIMAL
DECIMAL
avait (avant 5.0.3) certaines erreurs dues à l'utilisation de l'implémentation flottante.