Маючи на увазі, що я буду виконувати обчислення на лат / довгих парах, який тип даних найкраще підходить для використання з базою даних MySQL?
Маючи на увазі, що я буду виконувати обчислення на лат / довгих парах, який тип даних найкраще підходить для використання з базою даних MySQL?
Відповіді:
Використовуйте просторові розширення MySQL за допомогою GIS.
Google пропонує почати завершення PHP / MySQL для прикладу програми "Магазин-локатор" на Картах Google. У цьому прикладі вони зберігають значення lat / lng як "Float" довжиною "10,6"
FLOAT(10,6)
залишає 4 цифри для цілої частини координати. І ні, знак не рахується - це походить від (не) підписаного атрибута.
Double
для Laravel
В основному це залежить від точності, яка вам потрібна для ваших місць розташування. Використовуючи DOUBLE, ви отримаєте точність 3,5 нм. ДЕКІМАЛЬНА (8,6) / (9,6) опускається до 16см. ФЛОТ - 1,7 м ...
Ця дуже цікава таблиця має більш повний список: 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
Сподіваюсь, це допомагає.
Просторові розширення MySQL - найкращий варіант, оскільки у вас є повний перелік просторових операторів та індексів. Просторовий індекс дозволить вам дуже швидко виконувати обчислення на відстані. Будь ласка, майте на увазі, що станом на 6.0 просторове розширення все ще є незавершеним. Я не відкладаю MySQL Spatial, лише повідомляю про підводні камені, перш ніж ви занадто далеко підете на це.
Якщо ви суворо маєте справу з пунктами, і лише функція DISTANCE, це добре. Якщо вам потрібно здійснити будь-які обчислення за допомогою полігонів, ліній або буферних точок, просторові оператори не дають точних результатів, якщо ви не використовуєте оператора "relate". Дивіться попередження вгорі 21.5.6 . Зв'язки, такі як містить, всередині або перетинає, використовують MBR, а не точну геометричну форму (тобто Еліпс трактується як прямокутник).
Також відстані в MySQL Spatial складаються з тих же одиниць, що і ваша перша геометрія. Це означає, що якщо ви використовуєте десяткові градуси, то ваші вимірювання відстані проводяться в десяткових градусах. Це зробить дуже важко отримати точні результати, коли ви отримаєте фуртур від екватора.
Коли я зробив це для навігаційної бази даних, побудованої з ARINC424, я зробив неабияку кількість тестувань і оглянувшись на код, я використав ДЕКІМАЛЬНИЙ (18,12) (насправді числовий (18,12), тому що це firebird).
Поплавці та парні не такі точні, що може призвести до помилок округлення, що може бути дуже поганою справою. Я не можу пригадати, чи знайшов якісь реальні дані, які мали проблеми - але я впевнений, що неможливість точно зберігати у поплавці або подвійному може спричинити проблеми
Справа в тому, що при використанні градусів або радіанів ми знаємо діапазон значень - і дробова частина потребує найбільших цифр.
В MySQL Просторові розширення є хорошою альтернативою , оскільки вони слідують The OpenGIS Geometry Model . Я не використовував їх, тому що мені потрібно було зберігати свою базу даних.
a*b
не було рівних b*a
(для деяких значень). Було багато прикладів кілька , як: 2+2 = 3.9999
. Стандарт очистив багато безладу, і його «швидко» прийняли практично кожен апаратний та програмний продукт. Отже, ця дискусія є дійсною не лише з 2008 року, а й на третину століття.
Залежить від точності, яка вам потрібна.
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
Від: http://mysql.rjweb.org/doc.php/latlng
Підсумовувати:
DOUBLE
.DECIMAL(8,6)/(9,6)
.Станом на MySQL 5.7 , розгляньте можливість використання типів просторових даних (SDT), спеціально POINT
для зберігання однієї координати. До 5.7 SDT не підтримує індекси (за винятком 5,6, коли тип таблиці - MyISAM).
Примітка:
POINT
класу має бути порядок аргументів для зберігання координат POINT(latitude, longitude)
.ST_Distance
) та визначення того, чи міститься одна точка в іншій області ( ST_Contains
).CREATE TABLE geom (g GEOMETRY NOT NULL, SPATIAL INDEX(g)) ENGINE=MyISAM;
та попередження про обмеження SDT, як згадував Джеймс , можливо, ваша відповідь буде більш лаконічною та точною, допомагаючи і іншим людям. ..
Виходячи з цієї статті вікі http://en.wikipedia.org/wiki/Decimal_degrees#Accuracy відповідним типом даних у MySQL є Десятичний (9,6) для зберігання довготи та широти в окремих полях.
Використовуйте DECIMAL(8,6)
для широти (від 90 до -90 градусів) і DECIMAL(9,6)
для довготи (від 180 до -180 градусів). Для десятків застосувань - 6 знаків після коми. Обидва повинні бути "підписані", щоб враховувати негативні значення.
DECIMAL
Тип призначений для фінансових розрахунків, коли не floor/ceil
прийнято. Рівнина FLOAT
значно переважає DECIMAL
.
За даними Google Maps, не потрібно далеко їхати, найкращим є FLOAT (10,6) для лат і lng.
lat FLOAT( 10, 6 ) NOT NULL,
lng FLOAT( 10, 6 ) NOT NULL
FLOAT
синтаксис застарілий станом на mysql 8.0.17
. Тепер Mysql рекомендує просто використовувати FLOAT
без будь-яких точних параметрів dev.mysql.com/doc/refman/8.0/en/numeric-type-overview.html та dev.mysql.com/doc/refman/5.5/en/floating-point- types.html
Ми зберігаємо широту / довготу X 1 000 000 в нашій базі даних oracle як НОМЕРИ, щоб уникнути помилок з округленням.
Враховуючи, що широта / довгота до 6-го десяткового знаку складала 10 см точності, що було все, що нам було потрібно. Багато інших баз даних також зберігають lat / long до 6-го знаку після коми.
У зовсім іншій і простішій перспективі:
VARCHAR
), наприклад: " -0000.0000001, -0000.000000000000001 " (довжина 35, і якщо число має більше 7 десяткових цифр, воно стає округленим);google.maps.geometry.poly.containsLocation(latLng, bermudaTrianglePolygon))
Таким чином, вам не потрібно турбуватися про індексацію чисел та всі інші проблеми, пов’язані з типами даних, які можуть накрутити ваші координати.
залежно від вашої програми, я пропоную використовувати FLOAT (9,6)
просторові клавіші нададуть вам більше функцій, але за еталонами виробництва плаваючі плавки набагато швидше, ніж просторові клавіші. (0,01 VS 0,001 в AVG)
MySQL використовує подвійний для всіх плавців ... Тому використовуйте тип double. Використання float призведе до непередбачуваних округлих значень у більшості ситуацій
DOUBLE
. MySQL дозволяє зберігати дані як 4-байтові, так FLOAT
і 8-байтові DOUBLE
. Тож, ймовірно, буде втрата точності при зберіганні виразу в FLOAT
стовпчик.
Хоча це не оптимально для всіх операцій, якщо ви робите плиткові карти або працюєте з великою кількістю маркерів (крапок) лише з однією проекцією (наприклад, Меркатор, як очікують Карти Google та багато інших каркасних карток), я знайшов, що Я називаю "Складною системою координат" бути дуже, дуже зручною. В основному ви зберігаєте координати x і y пікселів при деякому збільшенні - я використовую рівень масштабу 23. Це має ряд переваг:
Я говорив про все це в недавньому дописі в блозі: http://blog.webfoot.com/2013/03/12/optimizing-map-tile-generation/
Я дуже здивований деякими відповідями / коментарями.
Чому на землі хтось готовий би добровільно "попередньо зменшити" точність, а потім пізніше виконати обчислення на гірші числа? Звучить в кінцевому рахунку дурно.
Якщо джерело має 64-бітову точність, безумовно, було б глухо добровільно фіксувати масштаб, наприклад. 6 десяткових знаків і обмежте точність максимум на 9 значущих цифр (що відбувається із загально запропонованим десятковим форматом 9.6).
Природно, зберігаються дані з точністю, яку має вихідний матеріал. Єдиною причиною зниження точності буде обмежений простір для зберігання.
Десятковий формат 9.6 викликає явище оснащення сітки. Це повинен бути самий останній крок, якщо він взагалі відбудеться.
Я б не запрошував накопичені помилки до свого гнізда.
TL; DR
Використовуйте FLOAT (8,5), якщо ви не працюєте в NASA / військових і не створюєте навігаційні системи літаків.
Щоб повністю відповісти на запитання, вам потрібно буде розглянути кілька речей:
Формат
Отже, перша частина відповіді була б - ви можете зберігати координати у форматі, який використовує ваша програма, щоб уникнути постійних перетворень вперед і назад та робити більш прості запити SQL.
Найімовірніше, ви використовуєте Карти Google або OSM для відображення своїх даних, а GMaps використовують формат "десяткових градусів 2". Так буде простіше зберігати координати в одному форматі.
Точність
Тоді ви хочете визначити необхідну точність. Звичайно, ви можете зберігати координати на кшталт "-32.608697550570334,21.278081997935146", але коли-небудь ви дбали про міліметри під час навігації до точки? Якщо ви не працюєте в НАСА і не робите супутників, ракет або траєкторій літаків, вам слід погодитися з точністю в кілька метрів.
Найпоширеніший формат - 5 цифр після крапок, що дає точність 50 см.
Приклад : між X, 21.278081 8 та X, 21.278081 9 є відстань 1 см . Таким чином, 7 цифр після крапки дають точність на 1/2 см, а 5 цифр після крапки дадуть точність на 1/2 метра (оскільки мінімальна відстань між окремими точками становить 1 м, тому помилка округлення не може бути більше її половини). Для більшості цивільних цілей цього має бути достатньо.
Формат градусів у десяткових хвилинах (40 ° 26,767 'N 79 ° 58,933 ′ Ш) дає точну точність, як і 5 цифр після крапки
Екологічно ефективне зберігання
Якщо ви вибрали десятковий формат, то ваша координата - пара (-32.60875, 21.27812). Очевидно, що 2 х (1 біт для знака, 2 цифри для градусів і 5 цифр для експонента) буде достатньо.
Тож тут я хотів би підтримати Alix Axel в коментарях, що пропозиція Google зберігати його в FLOAT (10,6) справді зайва, тому що для основної частини вам не потрібно 4 цифри (оскільки знак розділений, а широта обмежена до 90, а довгота обмежена 180). Ви можете легко використовувати FLOAT (8,5) для точності 1/2 м або FLOAT (9,6) для точності 50/2 см. Або ви навіть можете зберігати lat і long у відокремлених типах, тому що FLOAT (7,5) достатньо для lat. Дивіться посилання на поплавкові типи MySQL . Будь-яка з них буде, як звичайний FLOAT, і дорівнює 4 байтам у будь-якому випадку.
Зазвичай простір сьогодні не є проблемою, але якщо ви хочете реально оптимізувати сховище з якихось причин (відмова від відповідальності: не робіть попередньої оптимізації), ви можете стиснути lat (не більше 91 000 значень + знак) + long (ні більше 181 000 значень + знак) до 21 біт, що значно менше 2xFLOAT (8 байт == 64 біта)
Просторові функції в PostGIS набагато більш функціональні (тобто не обмежуються операціями BBOX), ніж функції в просторових функціях MySQL. Перевірте це: текст посилання
Широта становить від -90 до +90 (градусів), тому ДЕКІМАЛЬНА (10, 8) для цього нормальна
довжина варіюється від -180 до +180 (градусів), тому вам потрібно ДЕКІМАЛЬНИЙ (11, 8).
Примітка: Перше число - це загальна кількість збережених цифр, а друге - число після коми.
Коротко: lat DECIMAL(10, 8) NOT NULL, lng DECIMAL(11, 8) NOT NULL
Я пропоную використовувати тип даних Float для SQL Server.
Обчислення Lat Long вимагають точності, тому використовуйте певний тип десяткового типу і зробіть точність принаймні на 2 вище, ніж число, яке ви будете зберігати, щоб виконати математичні обчислення. Я не знаю про мої типи даних sql, але на SQL-сервері люди часто використовують float або real замість десяткових і потрапляють у проблеми, оскільки це оціночні числа, а не реальні. Тому просто переконайтеся, що тип даних, який ви використовуєте, є істинним десятковим типом, а не плаваючим десятковим типом, і вам повинно бути добре.
A FLOAT
повинен дати вам всю необхідну точність і бути кращим для порівняльних функцій, ніж зберігати кожну координату у вигляді рядка чи подібного.
Якщо ваша версія MySQL раніше, ніж 5.0.3, можливо, вам потрібно буде прислухатися до певних помилок порівняння з плаваючою комою .
До MySQL 5.0.3, стовпці DECIMAL зберігають значення з точною точністю, оскільки вони представлені у вигляді рядків, але обчислення значень DECIMAL проводяться за допомогою операцій з плаваючою комою. Станом на 5.0.3, MySQL виконує операції DECIMAL з точністю до 64 десяткових цифр, що повинно вирішити найпоширеніші проблеми з неточністю, якщо мова йде про стовпці DECIMAL
DECIMAL
були (раніше 5.0.3) певні помилки через використання плаваючої реалізації.