PostGIS 지오메트리 열에서 SELECT DISTINCT의 정밀도는 무엇입니까?


19

SELECT DISTINCTPostGIS 지오메트리 에서 연산자 의 정밀도가 무엇인지 궁금 합니다. 내 시스템에서 다음 쿼리는 5 카운트를 제공합니다. 즉, 삽입 된 포인트가 1e-5 미만으로 차이가 나는 경우 동일한 것으로 간주되며 이것이 설치 문제인 PostGIS의 기능인지 확실하지 않습니다. 또는 버그.

그것이 예상되는 행동인지 아는 사람이 있습니까?

CREATE TEMP TABLE test (geom geometry);
INSERT INTO test
    VALUES 
        (St_GeomFromText('POINT (0.1 0.1)')),
        (St_GeomFromText('POINT (0.001 0.001)')),
        (St_GeomFromText('POINT (0.0001 0.0001)')),
        (St_GeomFromText('POINT (0.00001 0.00001)')),
        (St_GeomFromText('POINT (0.000001 0.000001)')),
        (St_GeomFromText('POINT (0.0000001 0.0000001)')),
        (St_GeomFromText('POINT (0.00000001 0.00000001)')),
        (St_GeomFromText('POINT (0.000000001 0.000000001)'));

SELECT COUNT(*) FROM (SELECT DISTINCT geom FROM test) AS test;

 count 
-------
     5
(1 row)

나는 사용하고있다 :

$ psql --version
psql (PostgreSQL) 9.3.1

SELECT PostGIS_full_version();
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
POSTGIS="2.1.1 r12113" GEOS="3.4.2-CAPI-1.8.2 r3921" PROJ="Rel. 4.8.0, 6 March 2012" GDAL="GDAL 1.10.1, released 2013/08/26" LIBXML="2.7.3" LIBJSON="UNKNOWN" RASTER

OSX 10.9에서

답변:


18

나는 그것이 너무 거칠다는 것에 놀랐습니다. DISTINCT가 아니며, 그 자체로 '='연산자이며, 기하 도형에 대해 '색인 키의 동일성'으로 정의되어 실제로 '32 비트 경계 상자의 동일성 '을 의미합니다.

'='를 직접 사용하는 것과 동일한 효과를 볼 수 있습니다.

select 'POINT (0.000000001 0.000000001)'::geometry = 'POINT (0.000000001 0.000001)'::geometry;

select 'POINT (0.000000001 0.000000001)'::geometry = 'POINT (0.000000001 0.00001)'::geometry;

'='를 "직관적으로"동작하게하려면 불행히도 엄청난 계산 손실 (연산자 호출에 대해 명시적인 ST_Equals () 평가 수행) 또는 실질적으로 새로운 복잡한 코드 (더 큰 형상의 해시 값 저장, 더 작은 크기의 정확한 테스트 수행)가 수반됩니다. 하나, 즉석에서 올바른 코드 경로를 선택하는 등)

물론 현재 많은 응용 프로그램 / 사용자가 기존 동작을 내재화 했으므로 "개선"하면 많은 사람들에게 다운 그레이드됩니다. 대신 ST_AsBinary (geom)에서 집합을 계산하여 "정확한"구별을 수행 할 수 있으며, 이는 bytea 출력에서 ​​정확한 동등성 테스트를 수행합니다.


ST_AsBinary (geom)이 비교적 빠른 연산이라고 가정 할 수 있습니까?
Martin F

답변 주셔서 감사합니다, 이것은 동작을 잘 설명합니다. 실제로 geodjango 프로젝트를 진행 중이므로 __equals필터 를 사용 하여 ST_Equals 함수로 변환합니다.
yellowcap

1
예 ST_AsBinary가 빠릅니다. bytea의 평등 테스트에는 memcmp가 포함되어있을 수 있습니다. memcmp는 매우 빠른 op이므로 너무 끔찍해서는 안됩니다.
Paul Ramsey

@PaulRamsey, 여기서 무엇을 제안하고 있습니까? SELECT DISTINCT ST_AsBinary(geom)? 결과적으로 이진 표현을 제공합니다 geom. 당신은 할 수 있습니다 SELECT MAX(geom) FROM the_table GROUP BY ST_AsBinary(geom);( 절이 필드 자체가 아닌 함수 반환을 사용 하기 때문에 와 같은 집계 함수 MAX()가 필요 하다고 생각 합니다.) 괜찮습니까? SELECTGROUP BYST_AsBinary()
Martin Burch

7

다음 질문이 그에 대해 수행 할 수있는 이유에 대한 Paul Ramsey의 훌륭한 설명이 주어 집니다. 지오메트리 필드를 어떻게 수행하고 예상대로 수행합니까?SELECT DISTINCT

Paul의 대답에서 사용을 제안 SELECT MAX(geom) FROM the_table GROUP BY ST_AsBinary(geom);했지만 MAX()느리므로 분명히 테이블 스캔이 필요합니다.

대신, 이것이 더 빠르다는 것을 알았습니다.

SELECT DISTINCT ON (ST_AsBinary(geom)) geom FROM the_table;

4

PostGIS 2.4의 업데이트 만 SELECT DISTINCTOP의 포인트 데이터에 대해 올바르게 작동합니다.

CREATE TEMP TABLE test (geom geometry);
CREATE TABLE
user=> INSERT INTO test
user->     VALUES 
user->         (St_GeomFromText('POINT (0.1 0.1)')),
user->         (St_GeomFromText('POINT (0.001 0.001)')),
user->         (St_GeomFromText('POINT (0.0001 0.0001)')),
user->         (St_GeomFromText('POINT (0.00001 0.00001)')),
user->         (St_GeomFromText('POINT (0.000001 0.000001)')),
user->         (St_GeomFromText('POINT (0.0000001 0.0000001)')),
user->         (St_GeomFromText('POINT (0.00000001 0.00000001)')),
user->         (St_GeomFromText('POINT (0.000000001 0.000000001)'));
INSERT 0 8
user=> 
user=> SELECT COUNT(*) FROM (SELECT DISTINCT geom FROM test) AS test;
 count 
-------
     8
(1 row)

user=> select 'POINT (0.000000001 0.000000001)'::geometry = 'POINT (0.000000001 0.000001)'::geometry;
 ?column? 
----------
 f
(1 row)

user=> 
user=> select 'POINT (0.000000001 0.000000001)'::geometry = 'POINT (0.000000001 0.00001)'::geometry;
 ?column? 
----------
 f
(1 row)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.