MySQL 데이터베이스에 위도 / 경도를 저장할 때 사용하기에 이상적인 데이터 유형은 무엇입니까?
위도 / 경도 쌍에서 계산을 수행한다는 점을 염두에두고 MySQL 데이터베이스와 함께 사용하기에 가장 적합한 데이터 유형은 무엇입니까?
GIS와 함께 MySQL의 공간 확장 을 사용하십시오 .
Google은 Google지도를 사용하여 "Store Locator"애플리케이션의 예를 위해 PHP / MySQL 솔루션을 완성하기위한 시작을 제공합니다. 이 예제에서는 위도 / 경도 값을 "10,6"길이의 "Float"로 저장합니다.
http://code.google.com/apis/maps/articles/phpsqlsearch.html
기본적으로 위치에 필요한 정밀도에 따라 다릅니다. DOUBLE을 사용하면 3.5nm 정밀도를 얻을 수 있습니다. DECIMAL (8,6) / (9,6)은 16cm로 내려갑니다. FLOAT는 1.7m입니다 ...
이 흥미로운 테이블은 더 완전한 목록을 가지고 있습니다 : 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의 Spatial Extensions는 공간 연산자와 인덱스의 전체 목록을 자유롭게 사용할 수 있으므로 최상의 옵션입니다. 공간 인덱스를 사용하면 거리 기반 계산을 매우 빠르게 수행 할 수 있습니다. 6.0부터는 공간 확장이 여전히 불완전합니다. 나는 MySQL Spatial을 내려 놓지 않고 너무 멀리 가기 전에 함정을 알려줍니다.
점과 DISTANCE 기능 만 엄격하게 다루는 경우에는 문제가 없습니다. 다각형, 선 또는 버퍼 포인트를 사용하여 계산해야하는 경우 공간 연산자는 "관련"연산자를 사용하지 않으면 정확한 결과를 제공하지 않습니다. 21.5.6 맨 위에있는 경고를 참조하십시오 . 포함, 내부 또는 교차와 같은 관계는 정확한 지오메트리 모양이 아닌 MBR을 사용하고 있습니다 (예 : 타원은 사각형으로 처리됨).
또한 MySQL Spatial의 거리는 첫 번째 지오메트리와 동일한 단위입니다. 즉, 10 진수도를 사용하는 경우 거리 측정 값은 10 진수 도입니다. 이것은 적도에서 furthur를 얻을 때 정확한 결과를 얻는 것을 매우 어렵게 만듭니다.
ARINC424에서 작성된 탐색 데이터베이스에 대해이 작업을 수행했을 때 상당한 양의 테스트를 수행하고 코드를 다시 살펴 보았습니다 .DECIMAL (18,12) (실제로는 NUMERIC (18,12)는 파이어 버드이므로)을 사용했습니다.
플로트와 복식은 정확하지 않으며 반올림 오류가 발생하여 매우 나쁠 수 있습니다. 문제가있는 실제 데이터를 찾은 경우 기억이 나지 않습니다. 그러나 float 또는 double에 정확하게 저장할 수 없으면 문제가 발생할 수 있다고 확신합니다.
요점은 각도 또는 라디안을 사용할 때 값의 범위를 알고 분수 부분에 가장 많은 숫자가 필요하다는 것입니다.
MySQL의 공간 확장은 그들이 수행하기 때문에 좋은 대안이다 OpenGIS 지오메트리 모델 . 데이터베이스를 이식 가능하게 유지해야했기 때문에 사용하지 않았습니다.
필요한 정밀도에 따라 다릅니다.
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는 인덱스를 지원하지 않습니다 (테이블 유형이 MyISAM 인 경우 5.6 제외).
노트 :
POINT
클래스를 사용할 때 좌표 저장을위한 인수의 순서는이어야합니다POINT(latitude, longitude)
.- 공간 인덱스 를 작성하기 위한 특별한 구문이 있습니다 .
- SDT 사용의 가장 큰 이점은 공간 점 분석 기능에 액세스 할 수 있다는 것입니다 . 예를 들어 두 점 사이의 거리를 계산
ST_Distance
하고 ( ) 한 점이 다른 영역에 포함되어 있는지 여부를 결정합니다 (ST_Contains
).
이 위키 기사 http://en.wikipedia.org/wiki/Decimal_degrees#Accuracy를 기반으로 MySQL의 적절한 데이터 유형은 경도와 위도를 별도의 필드에 저장하기위한 Decimal (9,6)입니다.
사용 DECIMAL(8,6)
위도 (90 -90도)과 DECIMAL(9,6)
경도 (180 -180도)를 위해. 소수점 이하 6 자리는 대부분의 응용 프로그램에 적합합니다. 음수 값을 허용하려면 둘 다 "서명"해야합니다.
구글 맵스에 따르면, 가장 멀리 갈 필요는 없다.
우리는 두 배의 반올림 오류를 피하기 위해 위도 / 경도 X 1,000,000을 오라클 데이터베이스에 NUMBERS로 저장합니다.
소수점 6 자리까지의 위도 / 경도는 10cm의 정확도로 우리가 필요한 전부였습니다. 다른 많은 데이터베이스도 위도 / 경도를 소수점 6 자리까지 저장합니다.
완전히 다른 간단한 관점에서 :
- 지도, 마커, 다각형 등을 표시하기 위해 Google에 의존하는 경우 Google에서 계산을 수행하십시오!
- 서버에 리소스를 저장하고 위도 및 경도를 단일 문자열 (
VARCHAR
) 로 함께 저장하면됩니다 ( 예 : " -0000.0000001, -0000.000000000000001 "(35 개의 길이 및 숫자가 7 자리 이상인 경우 반올림 됨)). - Google이 숫자 당 7 자리 이상의 10 진수를 반환 하면 나중에 도망 치거나 미생물 을 감지하려는 경우를 대비하여 문자열에 저장된 데이터를 얻을 수 있습니다 .
- 거리 매트릭스 또는 지오메트리 라이브러리 를 사용하여 다음 과 같이 간단한 호출로 특정 영역에서 거리를 계산하거나 점을 감지 할 수 있습니다 .
google.maps.geometry.poly.containsLocation(latLng, bermudaTrianglePolygon))
- Google Maps API를 사용 하는 많은 "서버 측"API ( Python , Ruby on Rails , PHP , CodeIgniter , Laravel , Yii , Zend Framework 등)를 사용할 수 있습니다.
이 방법을 사용하면 숫자를 색인화하고 좌표를 망치는 데이터 유형과 관련된 다른 모든 문제에 대해 걱정할 필요가 없습니다.
응용 프로그램에 따라 FLOAT (9,6)를 사용하는 것이 좋습니다.
공간 키는 더 많은 기능을 제공하지만 프로덕션 벤치 마크에서는 플로트가 공간 키보다 훨씬 빠릅니다. (AVG에서는 0,01 VS 0,001)
MySQL은 모든 수레에 대해 double을 사용합니다. 따라서 double 유형을 사용하십시오. float를 사용하면 대부분의 상황에서 예기치 않은 반올림 값이 발생합니다
모든 작업에 최적은 아니지만지도 타일을 만들거나 하나의 투영만으로 많은 마커 (도트)로 작업하는 경우 (예 : Google지도와 같은 메르카토르 및 기타 미끄러운지도 프레임 워크가 예상하는) 저는 "Vast Coordinate System"을 호출하여 정말 편리합니다. 기본적으로 x 및 y 픽셀 좌표를 확대 / 축소 방식으로 저장합니다. 줌 레벨 23을 사용합니다. 여기에는 몇 가지 이점이 있습니다.
- 포인트를 처리 할 때마다 값 비싼 위도 / 경도에서 메르카토르 픽셀 변환을 한 번 수행합니다.
- 확대 / 축소 수준이 주어진 레코드에서 타일 좌표를 가져 오려면 오른쪽으로 한 번 이동해야합니다.
- 레코드에서 픽셀 좌표를 가져 오려면 하나의 오른쪽 이동과 하나의 비트 AND가 필요합니다.
- 시프트는 너무 가벼워서 SQL에서 실행하는 것이 실용적입니다. 즉, DISTINCT를 수행하여 픽셀 위치 당 하나의 레코드 만 리턴 할 수 있습니다. 이는 백엔드가 리턴 한 레코드 수를 줄이므로 처리량이 줄어 듭니다. 프런트 엔드.
나는 최근 블로그 게시물 에서이 모든 것에 대해 이야기했다 : http://blog.webfoot.com/2013/03/12/optimizing-map-tile-generation/
나는 일부 답변 / 의견에 크게 놀랐습니다.
왜 지구상에서 누구나 자발적으로 정밀도를 "감소"한 다음 나중에 더 나쁜 숫자에 대한 계산을 수행하려고합니까? 멍청한 소리.
소스의 64 비트 정밀도가 확실하다면 스케일을 자발적으로 고정하는 것은 멍청 할 것입니다. 소수점 이하 6 자리, 정밀도를 최대 9 자리까지 제한합니다 (일반적으로 제안되는 10 진수 9.6 형식으로 발생).
당연히 소스 자료의 정밀도로 데이터를 저장합니다. 정밀도를 낮추는 유일한 이유는 저장 공간이 제한되어 있기 때문입니다.
- 원본 정확도로 원본 수치 저장
- 소스에서 계산 된 수치를 계산에 정확하게 저장합니다 (예 : 애플리케이션 코드가 복식을 사용하는 경우 결과를 복식으로 저장)
10 진수 9.6- 포맷은 격자에 스냅 현상을 일으 킵니다. 그것이 일어날 수있는 마지막 단계가되어야합니다.
내 둥지에 누적 오류를 초대하지 않습니다.
PostGIS의 공간 함수는 MySQL 공간 함수보다 훨씬 더 기능적입니다 (즉, BBOX 작업으로 제한되지 않음). 확인 : 링크 텍스트
TL; DR
NASA / 군에서 일하지 않고 항공기를 해상 시스템으로 만들지 않는 경우 FLOAT (8,5)를 사용하십시오.
질문에 완전히 대답하려면 몇 가지 사항을 고려해야합니다.
체재
- 도 분 초 : 40 ° 26 ′ 46 ″ N 79 ° 58 ′ 56 ″ W
- 십진수도 : 40 ° 26.767 ′ N 79 ° 58.933 ′ W
- 소수점 1 : 40.446 ° N 79.982 ° W
- 소수점 2 : -32.60875, 21.27812
- 다른 집에서 만든 형식입니까? 아무도 당신이 당신의 자신의 홈 중심 좌표 시스템을 만들어 집으로 향하는 거리와 거리로 저장하는 것을 금지하지 않습니다. 이것은 작업중 인 특정 문제에 적합합니다.
따라서 응답의 첫 번째 부분은 응용 프로그램이 지속적인 변환을 피하고 SQL 쿼리를 간단하게 만드는 데 사용 하는 형식으로 좌표를 저장할 수 있다는 것 입니다.
대부분 Google지도 또는 OSM을 사용하여 데이터를 표시하고 GMaps는 "10 진수 2"형식을 사용합니다. 따라서 동일한 형식으로 좌표를 저장하는 것이 더 쉬울 것입니다.
정도
그런 다음 필요한 정밀도를 정의하고 싶습니다. 물론 "-32.608697550570334,21.278081997935146"과 같은 좌표를 저장할 수 있지만 해당 지점으로 이동하는 동안 밀리미터 정도 걱정 한 적이 있습니까? NASA에서 일하지 않고 위성이나 로켓 또는 비행기 궤도를 수행하지 않는 경우 몇 미터의 정확도로 괜찮을 것입니다.
일반적으로 사용되는 형식은 점 뒤에 5 자리이며 50cm의 정확도를 제공합니다.
예 : X, 21.278081 8 과 X, 21.278081 9 사이에 1cm 거리가 있습니다. 따라서 도트 뒤의 7 자리 숫자는 1 / 2cm 정밀도를 제공하고 도트 뒤의 5 자리 숫자는 1/2 미터 정확도를 제공합니다 (개별 포인트 사이의 최소 거리가 1m이므로 반올림 오차는 절반을 초과 할 수 없음). 대부분의 민사 목적으로는 충분합니다.
십진수 분 형식 (40 ° 26.767 ′ N 79 ° 58.933 ′ W)은 점 뒤에 5 자리와 정확히 동일한 정밀도를 제공합니다.
공간 효율적인 스토리지
10 진수 형식을 선택한 경우 좌표는 쌍입니다 (-32.60875, 21.27812). 분명히 2 x (부호는 1 비트, 도는 2 자리, 지수는 5 자리)이면 충분합니다.
그래서 여기 에서는 FLOAT (10,6)에 저장하라는 Google 제안이 실제로 추가된다는 의견에서 Alix Axel 을 지원하고 싶습니다. 주요 부분에 4 자리가 필요하지 않기 때문입니다 (기호가 구분되고 위도가 제한되어 있기 때문에) 경도는 90으로 제한되고 경도는 180으로 제한됩니다. 1 / 2m 정밀도에는 FLOAT (8,5)를, 50 / 2cm 정밀도에는 FLOAT (9,6)를 쉽게 사용할 수 있습니다. 또는 FLOAT (7,5)가 위도에 충분하기 때문에 위도 및 경도를 구분 된 유형으로 저장할 수도 있습니다. MySQL float 유형 참조를 참조하십시오 . 그들 중 하나는 일반적인 FLOAT와 같으며 어쨌든 4 바이트와 같습니다.
일반적으로 오늘날 공간은 문제가되지 않지만 어떤 이유로 든 저장소를 실제로 최적화하려면 (면책 조항 : 사전 최적화하지 마십시오) lat (91 000 값 + 부호) + long (no 2xFLOAT (8 바이트 == 64 비트)보다 훨씬 작은 21 비트 ~ 1 억 8 천 개 이상의 값 + 부호 )
위도의 범위는 -90에서 +90 (도)이므로 DECIMAL (10, 8)은 괜찮습니다.
경도는 -180에서 +180 (도)까지이며 DECIMAL (11, 8)이 필요합니다.
참고 : 첫 번째 숫자는 저장된 총 자릿수이고 두 번째 숫자는 소수점 뒤의 숫자입니다.
한마디로 : lat DECIMAL(10, 8) NOT NULL, lng DECIMAL(11, 8) NOT NULL
Lat Long 계산에는 정밀도가 필요하므로 일부 유형의 10 진수 유형을 사용하고 수학 계산을 수행하기 위해 저장할 숫자보다 최소 2 높은 정밀도를 만드십시오. 내 SQL 데이터 형식에 대해 모르지만 SQL Server 사람들은 종종 소수점 대신 실수 또는 실수를 사용하고 실제 숫자가 아닌 것으로 추정되므로 문제가 발생합니다. 따라서 사용하는 데이터 유형이 부동 소수점 유형이 아닌 진정한 십진 유형인지 확인하고 괜찮습니다.
A FLOAT
는 필요한 모든 정밀도를 제공하고 각 좌표를 문자열 등으로 저장하는 것보다 비교 기능에 더 좋습니다.
MySQL 버전이 5.0.3 이전 인 경우 특정 부동 소수점 비교 오류에 주의해야합니다 .
MySQL 5.0.3 이전에는 DECIMAL 열이 문자열로 표시되기 때문에 정확한 정밀도로 값을 저장하지만 DECIMAL 값에 대한 계산은 부동 소수점 연산을 사용하여 수행됩니다. 5.0.3부터 MySQL은 64 자리의 정밀도로 DECIMAL 연산을 수행하므로 DECIMAL 열과 관련하여 가장 일반적인 부정확성 문제를 해결해야합니다.
'Programing' 카테고리의 다른 글
URI에서 단어 구분 기호로 하이픈, 밑줄 또는 낙타 케이스? (0) | 2020.02.20 |
---|---|
반복자를 스트림으로 변환하는 방법? (0) | 2020.02.20 |
Android 튜토리얼의 대부분의 필드 (클래스 멤버)가 왜 m으로 시작합니까? (0) | 2020.02.19 |
매개 변수 이름 반영 : C # 람다 식 남용 또는 구문 광택? (0) | 2020.02.19 |
Python을 사용하여 Selenium WebDriver에서 WebElement의 HTML 소스 가져 오기 (0) | 2020.02.19 |