위도 / 경도 쌍에서 계산을 수행한다는 점을 염두에두고 MySQL 데이터베이스에 가장 적합한 데이터 유형은 무엇입니까?
위도 / 경도 쌍에서 계산을 수행한다는 점을 염두에두고 MySQL 데이터베이스에 가장 적합한 데이터 유형은 무엇입니까?
답변:
GIS와 함께 MySQL의 공간 확장 을 사용하십시오 .
Google은 Google지도를 사용하여 "Store Locator"응용 프로그램에 대한 PHP / MySQL 솔루션을 완성하기 시작했습니다. 이 예제에서는 위도 / 경도 값을 "10,6"길이의 "Float"로 저장합니다.
FLOAT(10,6)
. 좌표의 정수 부분에 4 자리를 남깁니다. 그리고 아니요, 부호는 계산되지 않습니다. 이는 부호없는 속성에서 비롯됩니다.
Double
Laravel 위해
기본적으로 위치에 필요한 정밀도에 따라 다릅니다. DOUBLE을 사용하면 3.5nm 정밀도를 얻을 수 있습니다. DECIMAL (8,6) / (9,6)은 16cm로 내려갑니다. 플로트는 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 지오메트리 모델 . 데이터베이스를 이식 가능하게 유지해야했기 때문에 사용하지 않았습니다.
a*b
동일하지 않은 기계도있었습니다 b*a
(일부 값의 경우). 다음과 같은 많은 예가있었습니다 : 2+2 = 3.9999
. 이 표준은 많은 혼란을 없애고 거의 모든 하드웨어와 소프트웨어에서 '빠르게'채택되었습니다. 따라서이 논의는 2008 년 이후가 아니라 3 세기 동안 유효했습니다.
필요한 정밀도에 따라 다릅니다.
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)
.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의 적절한 데이터 유형은 경도와 위도를 별도의 필드에 저장하기위한 Decimal (9,6)입니다.
사용 DECIMAL(8,6)
위도 (90 -90도)과 DECIMAL(9,6)
경도 (180 -180도)를 위해. 소수점 이하 6 자리는 대부분의 응용 프로그램에 적합합니다. 음수 값을 허용하려면 둘 다 "서명"해야합니다.
DECIMAL
유형은 floor/ceil
허용 되지 않는 재무 계산을위한 것입니다 . 평범한 것이 FLOAT
성능을 크게 능가 DECIMAL
합니다.
구글 맵스에 따르면, 가장 멀리 갈 필요는 없다.
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-
우리는 두 배의 반올림 오류를 피하기 위해 위도 / 경도 X 1,000,000을 오라클 데이터베이스에 NUMBERS로 저장합니다.
소수점 6 자리까지의 위도 / 경도는 10cm의 정확도로 우리가 필요한 전부였습니다. 다른 많은 데이터베이스들도 위도 / 경도를 소수점 6 자리까지 저장합니다.
완전히 다른 간단한 관점에서 :
VARCHAR
) 로 함께 저장하면됩니다 ( 예 : " -0000.0000001, -0000.000000000000001 "(35 개의 길이 및 숫자가 7 자리 이상인 경우 반올림 됨)).google.maps.geometry.poly.containsLocation(latLng, bermudaTrianglePolygon))
이 방법을 사용하면 숫자를 색인화하고 좌표를 망치는 데이터 유형과 관련된 다른 모든 문제에 대해 걱정할 필요가 없습니다.
응용 프로그램에 따라 FLOAT (9,6)를 사용하는 것이 좋습니다.
공간 키는 더 많은 기능을 제공하지만 프로덕션 벤치 마크에서는 플로트가 공간 키보다 훨씬 빠릅니다. (AVG에서는 0,01 VS 0,001)
MySQL은 모든 float에 double을 사용합니다. 따라서 double 유형을 사용하십시오. float를 사용하면 대부분의 상황에서 예기치 않은 반올림 값이 발생합니다.
DOUBLE
. MySQL을 사용하면 데이터를 4 바이트 또는 8 바이트로 저장할 수 있습니다 . 따라서 식을 열에 저장할 때 정밀도가 떨어질 수 있습니다 . FLOAT
DOUBLE
FLOAT
모든 작업에 최적은 아니지만지도 타일을 만들거나 하나의 투영만으로 많은 마커 (도트)로 작업하는 경우 (예 : Google지도와 같은 메르카토르 및 기타 미끄러운지도 프레임 워크에서 예상하는) 저는 "Vast Coordinate System"을 호출하여 정말 편리합니다. 기본적으로 x 및 y 픽셀 좌표를 확대 / 축소 방식으로 저장합니다. 줌 레벨 23을 사용합니다. 여기에는 몇 가지 이점이 있습니다.
나는 최근 블로그 게시물 에서이 모든 것에 대해 이야기했다 : http://blog.webfoot.com/2013/03/12/optimizing-map-tile-generation/
나는 일부 답변 / 의견에 크게 놀랐습니다.
왜 지구상에서 누구나 자발적으로 정밀도를 "감소"한 다음 나중에 더 나쁜 숫자에 대한 계산을 수행하려고합니까? 멍청한 소리.
소스의 64 비트 정밀도가 확실하다면 스케일을 자발적으로 고정하는 것은 멍청 할 것입니다. 소수점 이하 6 자리이며 정밀도를 최대 9 자리까지 제한합니다 (일반적으로 제안되는 10 진수 9.6 형식으로 발생).
당연히 소스 자료의 정확성으로 데이터를 저장합니다. 정밀도를 낮추는 유일한 이유는 저장 공간이 제한되어 있기 때문입니다.
10 진수 9.6- 포맷은 격자에 스냅 현상을 일으 킵니다. 그것이 일어나기 위해서는 그것이 마지막 단계가되어야합니다.
내 둥지에 누적 오류를 초대하지 않습니다.
TL; DR
NASA / 군에서 일하지 않고 항공기를 해상 시스템으로 만들지 않는 경우 FLOAT (8,5)를 사용하십시오.
질문에 완전히 대답하려면 몇 가지 사항을 고려해야합니다.
체재
따라서 응답의 첫 번째 부분은 좌표를 저장 하여 응용 프로그램이 지속적으로 변환하는 것을 피하고 간단한 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 천 개 이상의 값 + 부호 )
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 열과 관련하여 가장 일반적인 부정확성 문제를 해결해야합니다.
DECIMAL
부동 구현의 사용으로 인해 (5.0.3 이전) 특정 오류 가 있음을 지적합니다 .