지리 공간 데이터 타입

지리 공간 데이터 타입 (Geospatial data types)

Snowflake는 지구 표면의 점(point), 선(line), 다각형(polygon) 같은 지리 공간 기능을 기본(native)으로 지원해요. GEOGRAPHY와 GEOMETRY라는 두 가지 데이터 타입을 제공하며, 각각 지구를 구(sphere)로 보는 모델과 평면(planar) 좌표계 모델로 지형을 표현해요. 이 페이지에서는 두 타입의 차이, 입출력 포맷, 성능 최적화, 그리고 지리 기능 사용 방법을 다뤄요.

출처: Snowflake SQL Reference

본문

Snowflake는 지구 표면의 점, 선, 다각형 같은 지리 공간 기능을 기본(native)으로 지원해요.

Tip

검색 최적화 서비스(search optimization service)를 사용하면 쿼리 성능을 개선할 수 있어요. 자세한 내용은 검색 최적화 서비스를 참고해요.

데이터 타입

Snowflake는 지리 공간 데이터에 다음 데이터 타입을 제공해요.

  • 지구를 완벽한 구(sphere)로 모델링하는 GEOGRAPHY 데이터 타입.
  • 평면(Euclidean, Cartesian) 좌표계에서 지형을 나타내는 GEOMETRY 데이터 타입.

GEOGRAPHY 데이터 타입

GEOGRAPHY 데이터 타입은 WGS 84 표준(공간 참조 ID 4326; 자세한 내용은 https://epsg.io/4326)을 따르는 데이터 타입이에요.

지구의 점은 경도(longitude, -180도~+180도)와 위도(latitude, -90~+90)의 도(degrees)로 표현돼요. Snowflake는 GEOGRAPHY 좌표를 저장할 때 소수점 14자리를 사용해요. 데이터가 이 한도를 초과하는 소수 자릿수를 포함하면, 지정된 길이 제약을 준수하도록 좌표가 반올림돼요.

고도(altitude)는 현재 지원되지 않아요.

선분(line segments)은 지구 표면의 대권(great circle) 호로 해석돼요.

Snowflake는 또한 GEOGRAPHY 데이터 타입에서 동작하는 지리 공간 함수를 제공해요.

경도·위도 데이터, WKT, WKB, GeoJSON 같은 지리 공간 데이터가 있다면, 원래 포맷 그대로 VARCHAR, VARIANT, NUMBER 컬럼에 두기보다 GEOGRAPHY 컬럼으로 변환·저장하길 권장해요. 데이터를 GEOGRAPHY 컬럼에 저장하면 지리 공간 기능을 사용하는 쿼리의 성능이 크게 개선될 수 있어요.

GEOGRAPHY 데이터 타입의 지리 공간 함수 입력이 다각형을 나타낼 때, 다각형의 시작점과 끝점은 같아야 해요. 그렇지 않으면 함수가 오류를 반환할 수 있어요.

GEOMETRY 데이터 타입

GEOMETRY 데이터 타입은 평면(Euclidean, Cartesian) 좌표계에서 지형을 나타내요.

좌표는 실수 쌍(x, y)으로 표현돼요. 현재 2D 좌표만 지원돼요.

X와 Y의 단위는 GEOMETRY 객체와 연결된 공간 참조 시스템(SRS)에 의해 결정돼요. 공간 참조 시스템은 공간 참조 시스템 식별자(SRID) 번호로 식별돼요. GEOMETRY 객체를 만들 때 또는 ST_SETSRID를 호출해 SRID를 제공하지 않으면 SRID는 0이에요.

Snowflake는 GEOMETRY 좌표를 저장할 때 소수점 14자리를 사용해요. 데이터가 이 한도를 초과하는 소수 자릿수를 포함하면, 지정된 길이 제약을 준수하도록 좌표가 반올림돼요.

Snowflake는 GEOMETRY 데이터 타입에서 동작하는 지리 공간 함수 집합을 제공해요. 이 함수들에 대해:

  • 모든 함수는 평면 좌표를 가정해요(그 지오메트리가 비평면 SRS를 사용하더라도).
  • 측정 함수(예: ST_LENGTH)는 좌표계와 같은 단위를 사용해요.
  • 여러 GEOMETRY 표현식을 인자로 받는 함수(예: ST_DISTANCE)의 경우, 입력 표현식은 같은 SRS로 정의되어야 해요.

지리 공간 입출력

다음 섹션들은 지리 공간 데이터를 읽고 쓸 때 지원되는 표준 포맷과 객체 유형을 다뤄요.

  • 지원되는 표준 입출력 포맷
  • 지원되는 지리 공간 객체 유형
  • 결과 집합에 대한 출력 포맷 지정
  • GEOGRAPHY 데이터 삽입·쿼리 예제

지원되는 표준 입출력 포맷

GEOGRAPHY와 GEOMETRY 데이터 타입은 입출력에 다음 표준 산업 포맷을 지원해요.

다음 Open Geospatial Consortium의 Simple Feature Access 참조도 유용할 수 있어요.

이 표준에서 벗어나는 부분은 Snowflake 문서에 명시적으로 표기돼요.

GEOGRAPHY 값에 대한 GeoJSON 처리

WKT와 WKB 표준은 포맷만 지정해요. WKT/WKB 객체의 의미론(semantics)은 참조 시스템(예: 평면 또는 구)에 따라 달라져요.

반면 GeoJSON 표준은 포맷과 그 의미론을 모두 지정해요: GeoJSON 점은 명시적으로 WGS 84 좌표이고, GeoJSON 선분은 평면 가장자리(직선)예요.

이와 달리 Snowflake GEOGRAPHY 데이터 타입은 GeoJSON 포맷에서 입력되거나 출력되는 선분을 포함한 모든 선분을 대권 호로 해석해요. 본질적으로 Snowflake는 GeoJSON을 구형 의미론(spherical semantics)을 가진 JSON 형식의 WKT로 취급해요.

GEOGRAPHY 값에 대한 EWKT와 EWKB 처리

EWKT와 EWKB는 PostGIS가 도입한 비표준 포맷이에요. 이들은 데이터와 함께 사용할 좌표 참조 시스템을 지정하는 공간 참조 시스템 식별자(SRID)를 포함함으로써 WKT와 WKB 포맷을 확장해요. Snowflake는 현재 WGS84만 지원하며, 이는 SRID=4326에 매핑돼요.

기본적으로 Snowflake는 EWKB 또는 EWKT 입력 값에 4326이 아닌 SRID가 포함되면 오류를 발생시켜요. 반대로 모든 EWKB·EWKT 출력 값은 SRID=4326이에요.

지원되는 지리 공간 객체 유형

GEOGRAPHY와 GEOMETRY 데이터 타입은 다음 유형의 지리 공간 객체를 저장할 수 있어요.

  • WKT / WKB / EWKT / EWKB / GeoJSON 지리 공간 객체:
    • Point
    • MultiPoint
    • LineString
    • MultiLineString
    • Polygon
    • MultiPolygon
    • GeometryCollection
  • 다음 GeoJSON 특유의 지리 공간 객체:
    • Feature
    • FeatureCollection

결과 집합에 대한 출력 포맷 지정

세션 파라미터 GEOGRAPHY_OUTPUT_FORMATGEOMETRY_OUTPUT_FORMAT은 각각 결과 집합에서 GEOGRAPHY와 GEOMETRY 컬럼의 렌더링을 제어해요.

이 파라미터는 다음 값 중 하나를 가질 수 있어요.

파라미터 값 설명
GeoJSON (기본값) GEOGRAPHY / GEOMETRY 결과가 GeoJSON 포맷의 OBJECT로 렌더링돼요.
WKT GEOGRAPHY / GEOMETRY 결과가 WKT 포맷의 VARCHAR로 렌더링돼요.
WKB GEOGRAPHY / GEOMETRY 결과가 WKB 포맷의 BINARY로 렌더링돼요.
EWKT GEOGRAPHY / GEOMETRY 결과가 EWKT 포맷의 VARCHAR로 렌더링돼요.
EWKB GEOGRAPHY / GEOMETRY 결과가 EWKB 포맷의 BINARY로 렌더링돼요.

EWKTEWKB의 경우 출력의 SRID는 항상 4326이에요. GEOGRAPHY 값에 대한 EWKT와 EWKB 처리를 참고해요.

이 파라미터는 Snowflake UI와 SnowSQL 명령줄 클라이언트를 포함한 모든 클라이언트, 그리고 JDBC, ODBC, Node.js, Python 등의 드라이버와 커넥터에 영향을 줘요.

예를 들어 JDBC Driver는 GEOGRAPHY 타입 결과 컬럼(이 예제에서 컬럼 i)에 대해 다음 메타데이터를 반환해요.

  • GEOGRAPHY_OUTPUT_FORMAT='GeoJSON' 또는 GEOMETRY_OUTPUT_FORMAT='GeoJSON'인 경우:
    • ResultSetMetaData.getColumnType(i)java.sql.Types.VARCHAR를 반환해요.
    • ResultSetMetaData.getColumnClassName(i)"java.lang.String"을 반환해요.
  • GEOGRAPHY_OUTPUT_FORMAT='WKT' 또는 'EWKT', 또는 GEOMETRY_OUTPUT_FORMAT='WKT' 또는 'EWKT'인 경우:
    • ResultSetMetaData.getColumnType(i)java.sql.Types.VARCHAR를 반환해요.
    • ResultSetMetaData.getColumnClassName(i)"java.lang.String"을 반환해요.
  • GEOGRAPHY_OUTPUT_FORMAT='WKB' 또는 'EWKB', 또는 GEOMETRY_OUTPUT_FORMAT='WKB' 또는 'EWKB'인 경우:
    • ResultSetMetaData.getColumnType(i)java.sql.Types.BINARY를 반환해요.
    • ResultSetMetaData.getColumnClassName(i)"[B"(byte 배열)을 반환해요.

Note

데이터베이스 특정 타입 이름 검색 API(JDBD의 getColumnTypeName과 ODBC의 SQL_DESC_TYPE_NAME 디스크립터)는 GEOGRAPHY_OUTPUT_FORMATGEOMETRY_OUTPUT_FORMAT 파라미터의 값과 무관하게 타입 이름으로 항상 GEOGRAPHYGEOMETRY를 반환해요. 자세한 내용은 다음을 참고해요.

GEOGRAPHY 데이터 삽입·쿼리 예제

아래 코드는 GEOGRAPHY 데이터 타입의 샘플 입력과 출력을 보여 줘요. 다음에 주의해요.

  • WKT, EWKT, GeoJSON의 좌표에서는 경도가 위도보다 먼저 나와요(예: POINT(lon lat)).
  • WKB와 EWKB 출력의 경우 BINARY_OUTPUT_FORMAT 파라미터가 HEX(파라미터의 기본값)로 설정되어 있다고 가정해요.

다음 예제는 GEOGRAPHY 컬럼이 있는 테이블을 만들고 WKT 포맷으로 데이터를 삽입한 뒤, 다양한 출력 포맷으로 데이터를 반환해요.

CREATE OR REPLACE TABLE geospatial_table (id INTEGER, g GEOGRAPHY);
INSERT INTO geospatial_table VALUES
  (1, 'POINT(-122.35 37.55)'),
  (2, 'LINESTRING(-124.20 42.00, -120.01 41.99)');
ALTER SESSION SET GEOGRAPHY_OUTPUT_FORMAT='GeoJSON';
SELECT g
  FROM geospatial_table
  ORDER BY id;

+------------------------+
| G                      |
|------------------------|
| {                      |
|   "coordinates": [     |
|     -122.35,           |
|     37.55              |
|   ],                   |
|   "type": "Point"      |
| }                      |
| {                      |
|   "coordinates": [     |
|     [                  |
|       -124.2,          |
|       42               |
|     ],                 |
|     [                  |
|       -120.01,         |
|       41.99            |
|     ]                  |
|   ],                   |
|   "type": "LineString" |
| }                      |
+------------------------+
ALTER SESSION SET GEOGRAPHY_OUTPUT_FORMAT='WKT';
SELECT g
  FROM geospatial_table
  ORDER BY id;

+-------------------------------------+
| G                                   |
|-------------------------------------|
| POINT(-122.35 37.55)                |
| LINESTRING(-124.2 42,-120.01 41.99) |
+-------------------------------------+
ALTER SESSION SET GEOGRAPHY_OUTPUT_FORMAT='WKB';
SELECT g
  FROM geospatial_table
  ORDER BY id;

+------------------------------------------------------------------------------------+
| G                                                                                  |
|------------------------------------------------------------------------------------|
| 01010000006666666666965EC06666666666C64240                                         |
| 010200000002000000CDCCCCCCCC0C5FC00000000000004540713D0AD7A3005EC01F85EB51B8FE4440 |
+------------------------------------------------------------------------------------+
ALTER SESSION SET GEOGRAPHY_OUTPUT_FORMAT='EWKT';
SELECT g
  FROM geospatial_table
  ORDER BY id;

+-----------------------------------------------+
| G                                             |
|-----------------------------------------------|
| SRID=4326;POINT(-122.35 37.55)                |
| SRID=4326;LINESTRING(-124.2 42,-120.01 41.99) |
+-----------------------------------------------+
ALTER SESSION SET GEOGRAPHY_OUTPUT_FORMAT='EWKB';
SELECT g
  FROM geospatial_table
  ORDER BY id;

+--------------------------------------------------------------------------------------------+
| G                                                                                          |
|--------------------------------------------------------------------------------------------|
| 0101000020E61000006666666666965EC06666666666C64240                                         |
| 0102000020E610000002000000CDCCCCCCCC0C5FC00000000000004540713D0AD7A3005EC01F85EB51B8FE4440 |
+--------------------------------------------------------------------------------------------+

Snowflake에서 지리 공간 데이터 사용하기

다음 섹션들은 Snowflake에서 지리 공간 데이터를 작업하는 방법을 다뤄요.

  • GEOMETRY에서 서로 다른 SRID 사용의 영향 이해
  • GEOMETRY 객체의 공간 참조 시스템(SRS)과 SRID 변경
  • GEOGRAPHY와 GEOMETRY 컬럼에 DML 연산 수행
  • 스테이지에서 지리 공간 데이터 로딩
  • Java UDF와 지리 공간 데이터 사용
  • JavaScript UDF와 지리 공간 데이터 사용
  • Python UDF와 지리 공간 데이터 사용
  • H3와 GEOGRAPHY 객체 사용

GEOMETRY에서 서로 다른 SRID 사용의 영향 이해

GEOMETRY 컬럼에는 서로 다른 SRID를 가진 객체를 삽입할 수 있어요. 컬럼에 둘 이상의 SRID가 포함되면 일부 중요한 성능 최적화가 적용되지 않아요. 특히 지리 공간 술어(predicate)로 조인할 때 쿼리가 느려질 수 있어요.

GEOMETRY 객체의 공간 참조 시스템(SRS)과 SRID 변경

기존 GEOMETRY 객체의 SRSSRID를 변경하려면, 새 SRID를 전달하며 ST_TRANSFORM 함수를 호출해요. 이 함수는 새 SRID와 SRS를 사용하도록 변환된 좌표를 가진 새 GEOMETRY 객체를 반환해요. 예를 들어 SRID 32633의 SRS를 사용하는 geometry_expression에 대한 GEOMETRY 객체를 반환하려면 다음 문을 실행해요.

SELECT ST_TRANSFORM(geometry_expression, 32633);

기존 GEOMETRY 객체에 원래 SRID가 올바르게 설정되어 있지 않으면, 원래 SRID를 추가 인자로 지정해요. 예를 들어 geometry_expression이 SRID 4326을 사용하는 GEOMETRY 객체이고, 이를 SRID 28992를 사용하도록 변환하려면 다음 문을 실행해요.

SELECT ST_TRANSFORM(geometry_expression, 4326, 28992);

GEOMETRY 객체가 SRS에 대해 올바른 좌표를 사용하지만 SRID가 잘못되어 있다면, ST_SETSRID 함수를 호출해 SRID를 수정할 수 있어요. 예를 들어 다음 문은 좌표는 그대로 두고 geometry_expression의 SRID를 4326으로 설정해요.

SELECT ST_SETSRID(geometry_expression, 4326);

GEOGRAPHY와 GEOMETRY 컬럼에 DML 연산 수행

GEOGRAPHY 또는 GEOMETRY 컬럼이 DML 연산(INSERT, COPY, UPDATE, MERGE, CREATE TABLE AS…)의 대상일 때, 컬럼의 소스 표현식은 다음 유형 중 하나일 수 있어요.

  • GEOGRAPHY 또는 GEOMETRY: GEOGRAPHY 또는 GEOMETRY 타입의 표현식은 보통 파싱 함수, 생성자(constructor) 함수, 또는 기존 GEOGRAPHY·GEOMETRY 컬럼의 결과예요. 지원되는 함수와 함수 범주의 전체 목록은 지리 공간 함수를 참고해요.
  • VARCHAR: WKT, WKB(hex 포맷), EWKT, EWKB(hex 포맷) 또는 GeoJSON 포맷 문자열로 해석돼요(TO_GEOGRAPHY(VARCHAR) 참고).
  • BINARY: WKB 바이너리로 해석돼요(TO_GEOGRAPHY(BINARY)TO_GEOMETRY(BINARY) 참고).
  • VARIANT: GeoJSON 객체로 해석돼요(TO_GEOGRAPHY(VARIANT)TO_GEOMETRY(VARIANT) 참고).

스테이지에서 지리 공간 데이터 로딩

스테이지의 CSV 또는 JSON/AVRO 파일에서 (복사 변환 없이) GEOGRAPHY 컬럼으로 직접 데이터를 로드할 수 있어요.

  • CSV: 해당 CSV 컬럼의 문자열 값이 GeoJSON, WKT, EWKT, WKB, or EWKB로 파싱돼요(TO_GEOGRAPHY(VARCHAR) 참고).
  • JSON/AVRO: 파일의 JSON 값이 GeoJSON으로 해석돼요(TO_GEOGRAPHY(VARIANT) 참고).

GEOGRAPHY 값에 대한 GeoJSON 처리도 참고해요.

다른 파일 포맷(Parquet, ORC 등)에서 데이터를 로딩하는 것은 COPY 변환으로 가능해요.

Java UDF와 지리 공간 데이터 사용

Java UDF는 GEOGRAPHY 타입을 인자와 반환 값으로 허용해요. 자세한 내용은 SQL-Java 데이터 타입 매핑인라인 Java UDF에 GEOGRAPHY 값 전달을 참고해요.

JavaScript UDF와 지리 공간 데이터 사용

JavaScript UDF는 GEOGRAPHY 또는 GEOMETRY 타입을 인자와 반환 값으로 허용해요.

JavaScript UDF에 GEOGRAPHY 또는 GEOMETRY 타입의 인자가 있으면, UDF 본문 안에서 그 인자는 GeoJSON 포맷의 JSON 객체로 보여요.

JavaScript UDF가 GEOGRAPHY 또는 GEOMETRY를 반환하면, UDF 본문은 GeoJSON 포맷의 JSON 객체를 반환해야 해요.

예를 들어 다음 두 JavaScript UDF는 내장 함수 ST_X와 ST_MAKEPOINT와 대략 동등해요.

CREATE OR REPLACE FUNCTION my_st_x(g GEOGRAPHY) RETURNS REAL
LANGUAGE JAVASCRIPT
AS
$$
  if (G["type"] != "Point")
  {
     throw "Not a point"
  }
  return G["coordinates"][0]
$$;

CREATE OR REPLACE FUNCTION my_st_makepoint(lng REAL, lat REAL) RETURNS GEOGRAPHY
LANGUAGE JAVASCRIPT
AS
$$
  g = {}
  g["type"] = "Point"
  g["coordinates"] = [ LNG, LAT ]
  return g
$$;

Python UDF와 지리 공간 데이터 사용

Python UDF는 GEOGRAPHY와 GEOMETRY 타입을 인자와 반환 값으로 허용해요.

Python UDF에 GEOGRAPHY 또는 GEOMETRY 타입의 인자가 있으면, 그 인자는 UDF 본문 안에서 Python dict 객체로 변환되는 GeoJSON 객체로 표현돼요.

Python UDF가 GEOGRAPHY 또는 GEOMETRY를 반환하면, UDF 본문은 GeoJSON의 구조를 따르는 Python dict 객체를 반환해야 해요.

예를 들어 이 Python UDF는 복합 GEOGRAPHY 타입을 구성하는 서로 다른 지오메트리 수를 반환해요.

CREATE OR REPLACE FUNCTION py_numgeographys(geo GEOGRAPHY)
RETURNS INTEGER
LANGUAGE PYTHON
RUNTIME_VERSION = 3.10
PACKAGES = ('shapely')
HANDLER = 'udf'
AS $$
from shapely.geometry import shape, mapping
def udf(geo):
    if geo['type'] not in ('MultiPoint', 'MultiLineString', 'MultiPolygon', 'GeometryCollection'):
        raise ValueError('Must be a composite geometry type')
    else:
        g1 = shape(geo)
        return len(g1.geoms)
$$;

Snowflake Labs에서 더 많은 Python UDF 샘플을 확인해요. 일부는 복잡한 공간 조작을 가능하게 하거나 데이터 수집을 단순화해요. 예를 들어 이 UDF는 Shapefiles(.SHP), TAB, KML, GPKG 등 기본적으로 지원되지 않는 포맷을 읽을 수 있게 해 줘요.

Note

Snowflake Labs의 코드 샘플은 참조 및 교육 목적으로만 제공돼요. 이 코드 샘플은 어떤 Service Level Agreement에도 포함되지 않아요.

H3와 GEOGRAPHY 객체 사용

H3_는 세계를 이산 전역 격자 체계(discrete global grid system)의 육각형 셀로 분할하는 계층적 지리 공간 인덱스예요.

Snowflake는 H3를 GEOGRAPHY 객체와 함께 사용할 수 있는 SQL 함수를 제공해요. 이 함수들로 다음을 할 수 있어요.

  • Point를 나타내는 GEOGRAPHY 객체에 대한 H3 셀 ID(인덱스) 가져오기(그 반대도 가능).
  • GEOGRAPHY 객체를 덮는 최소 H3 셀 집합의 ID 가져오기.
  • Polygon을 나타내는 GEOGRAPHY 객체 안에 중심점(centroid)이 있는 H3 셀의 ID 가져오기.
  • H3 셀의 경계를 나타내는 GEOGRAPHY 객체 가져오기.
  • 주어진 H3 셀의 부모와 자식 가져오기.
  • H3 셀 중심점의 경도와 위도 가져오기(그 반대도 가능).
  • H3 셀의 해상도(resolution) 가져오기.
  • H3 셀 ID의 16진수 표현 가져오기(그 반대도 가능).

이 함수들에 대한 자세한 내용은 지리 공간 함수를 참고해요.

사용할 지리 공간 데이터 타입 선택 (GEOGRAPHY 또는 GEOMETRY)

다음 섹션들은 GEOGRAPHY와 GEOMETRY 데이터 타입의 차이를 설명해요.

  • GEOGRAPHY와 GEOMETRY의 차이 이해
  • GEOGRAPHY와 GEOMETRY 데이터 타입 비교 예제
  • 입력 데이터 검증의 차이 이해

GEOGRAPHY와 GEOMETRY의 차이 이해

GEOGRAPHY와 GEOMETRY 데이터 타입은 모두 지리 공간 지형을 정의하지만, 다른 모델을 사용해요. 다음 표는 차이를 요약해요.

GEOGRAPHY 데이터 타입 GEOMETRY 데이터 타입
구(sphere) 위의 지형 정의 평면(plane) 위의 지형 정의
- WGS84 좌표계만. SRID는 항상 4326. - 모든 좌표계 지원.
- 좌표는 도(degrees) 단위의 위도(-9090)와 경도(-180180). - 좌표 값의 단위는 공간 참조 시스템이 정의.
- 측정 연산(ST_LENGTH, ST_AREA 등) 결과는 미터(meters). - 측정 연산(ST_LENGTH, ST_AREA 등) 결과는 좌표와 같은 단위. 예: 입력 좌표가 도이면 결과도 도.
- 선분은 지구 표면의 대권(great circle) 호로 해석. - 선분은 평면의 직선으로 해석.

GEOGRAPHY와 GEOMETRY 데이터 타입 비교 예제

다음 예제들은 GEOGRAPHY와 GEOMETRY 데이터 타입을 입력으로 사용할 때 지리 공간 함수의 출력을 비교해요.

예제 1: 베를린과 샌프란시스코 사이 거리 쿼리

다음 표는 GEOGRAPHY 타입과 GEOMETRY 타입의 ST_DISTANCE 출력을 비교해요.

GEOGRAPHY 입력을 사용한 ST_DISTANCE GEOMETRY 입력을 사용한 ST_DISTANCE
```
SELECT ST_DISTANCE(
ST_POINT(13.4814, 52.5015),
ST_POINT(-121.8212, 36.8252))

AS distance_in_meters;

+--------------------+ | DISTANCE_IN_METERS | |--------------------| | 9182410.99227821 | +--------------------+

| ```
SELECT ST_DISTANCE(
    ST_GEOMPOINT(13.4814, 52.5015),
    ST_GEOMPOINT(-121.8212, 36.8252))
  AS distance_in_degrees;

+---------------------+
| DISTANCE_IN_DEGREES |
|---------------------|
|       136.207708844 |
+---------------------+
``` |

위 예제에서 보듯이:

- GEOGRAPHY 입력 값으로는 입력 좌표가 도이고 출력 값은 미터예요. (결과는 9,182 km.)
- GEOMETRY 입력 값으로는 입력 좌표와 출력 값이 모두 도예요. (결과는 136.208도.)

##### 예제 2: 독일의 면적 쿼리

다음 표는 GEOGRAPHY 타입과 GEOMETRY 타입의 [ST_AREA](</sql-reference/functions/st_area>) 출력을 비교해요.

| GEOGRAPHY 입력을 사용한 ST_AREA | GEOMETRY 입력을 사용한 ST_AREA |
|---|---|
| ```
SELECT ST_AREA(border) AS area_in_sq_meters
  FROM world_countries
  WHERE name = 'Germany';

+-------------------+
| AREA_IN_SQ_METERS |
|-------------------|
|  356379183635.591 |
+-------------------+
``` |
| ```
SELECT ST_AREA(border) as area_in_sq_degrees
  FROM world_countries_geom
  WHERE name = 'Germany';

+--------------------+
| AREA_IN_SQ_DEGREES |
|--------------------|
|       45.930026848 |
+--------------------+
``` |

위 예제에서 보듯이:

- GEOGRAPHY 입력 값으로는 입력 좌표가 도이고 출력 값은 제곱미터예요. 결과는 356,379 km^2.
- GEOMETRY 입력 값으로는 입력 좌표가 도이고 출력 값은 제곱도(square degrees)예요. 결과는 45.930 제곱도.

##### 예제 3: 베를린에서 샌프란시스코까지의 선과 겹치는 국가 이름 쿼리

다음 표는 GEOGRAPHY 타입과 GEOMETRY 타입의 [ST_INTERSECTS](</sql-reference/functions/st_intersects>) 출력을 비교해요.

| GEOGRAPHY 입력을 사용한 ST_INTERSECTS | GEOMETRY 입력을 사용한 ST_INTERSECTS |
|---|---|
| ```
SELECT name FROM world_countries WHERE
  ST_INTERSECTS(border,
    TO_GEOGRAPHY(
      'LINESTRING(13.4814 52.5015, -121.8212 36.8252)'
    ));

+--------------------------+
| NAME                     |
|--------------------------|
|                  Germany |
|                  Denmark |
|                  Iceland |
|                Greenland |
|                   Canada |
| United States of America |
+--------------------------+
``` |
| ```
SELECT name FROM world_countries_geom WHERE
  ST_INTERSECTS(border,
    TO_GEOMETRY(
      'LINESTRING(13.4814 52.5015, -121.8212 36.8252)'
    ));

+--------------------------+
| NAME                     |
|--------------------------|
|                  Germany |
|                  Belgium |
|              Netherlands |
|           United Kingdom |
| United States of America |
+--------------------------+
``` |

#### 입력 데이터 검증의 차이 이해

입력 형태에 대한 GEOMETRY 또는 GEOGRAPHY 객체를 만들려면 [OGC Simple Features 규칙](<https://www.ogc.org/standards/sfa>)에 따라 형상이 잘 구성되고 유효해야 해요. 다음 섹션들은 GEOMETRY와 GEOGRAPHY 사이에서 입력 데이터의 유효성이 어떻게 다른지 설명해요.

##### 어떤 형상은 유효한 GEOGRAPHY지만 유효하지 않은 GEOMETRY일 수 있음

주어진 형상은 유효한 GEOGRAPHY 객체일 수 있지만 유효하지 않은 GEOMETRY 객체일 수 있고, 그 반대도 가능해요.

예를 들어 자기 교차(self-intersecting) 다각형은 OGC 규칙으로 허용되지 않아요. 주어진 점 집합은 Cartesian 영역에서는 교차하지만 구에서는 교차하지 않는 가장자리를 정의할 수 있어요. 다음 다각형을 고려해요:

POLYGON((0 50, 25 50, 50 50, 0 50))


Cartesian 영역에서 이 다각형은 선으로 퇴화되어 결과적으로 유효하지 않아요.

하지만 구에서는 이 같은 다각형이 자기 자신과 교차하지 않으므로 유효해요.

##### 변환과 생성자 함수는 검증을 다르게 처리해요

입력 데이터가 유효하지 않을 때, GEOMETRY와 GEOGRAPHY 함수는 검증을 다르게 처리해요.

- GEOGRAPHY 객체로 구성·변환하는 일부 함수는 닫히지 않은 루프, 스파이크(spikes), 컷(cuts), 다각형의 자기 교차 루프 같은 문제를 처리하기 위해 형상을 복구(repair)하려 시도할 수 있어요. 예를 들어 [TO_GEOGRAPHY](</sql-reference/functions/to_geography>) 함수나 [ST_MAKEPOLYGON](</sql-reference/functions/st_makepolygon>) 함수로 다각형을 구성할 때, 함수는 지구 절반 이상을 덮는 다각형이 생성되지 않도록 루프의 방향을 수정해요. 그러나 [ST_MAKEPOLYGONORIENTED](</sql-reference/functions/st_makepolygonoriented>) 함수는 루프 방향을 수정하려 시도하지 않아요.

함수가 형상 복구에 성공하면 GEOGRAPHY 객체를 반환해요.

- GEOMETRY 객체로 구성·변환하는 함수(예: [TO_GEOMETRY](</sql-reference/functions/to_geometry>))는 형상을 복구하는 기능을 지원하지 않아요.

### GEOGRAPHY와 GEOMETRY 사이 변환

Snowflake는 GEOGRAPHY 객체에서 GEOMETRY 객체로(그 반대로도) 변환하는 것을 지원해요. Snowflake는 서로 다른 공간 참조 시스템(SRS)을 사용하는 객체의 변환(transformation)도 지원해요.

다음 예제는 점을 나타내는 GEOGRAPHY 객체를 [SRID](<https://en.wikipedia.org/wiki/Spatial_reference_system#Identifier>) 0인 GEOMETRY 객체로 변환해요.

SELECT TO_GEOMETRY(TO_GEOGRAPHY('POINT(-122.306100 37.554162)'));


새 GEOMETRY 객체의 SRID를 설정하려면 생성자 함수에 SRID를 인자로 전달해요. 예를 들어:

SELECT TO_GEOMETRY(TO_GEOGRAPHY('POINT(-122.306100 37.554162)', 4326));


기존 GEOMETRY 객체의 SRID를 설정해야 한다면, GEOMETRY 객체의 공간 참조 시스템(SRS)과 SRID 변경을 참고해요.

### 지리 공간 술어가 있는 쿼리에 대한 자동 성능 최적화

Snowflake는 지리 공간 술어가 있는 쿼리에 대해 다음 성능 최적화를 자동으로 구현해요.

- GeoJoin
- GEOMETRY 술어에 대한 지리 공간 가지치기(geospatial pruning)

#### GeoJoin

_GeoJoin_ 은 지리 공간 조인을 위한 Snowflake 쿼리 최적화 기능이에요. ST_INTERSECTS, ST_CONTAINS, ST_DWITHIN 같은 지리 공간 함수를 호출하는 술어를 기반으로 테이블을 조인할 때 성능을 개선하는 특수한 조인 재작성(join rewrite) 최적화예요. 예를 들어 GeoJoin은 특정 지리 영역 안의 모든 상점을 찾는 데 사용될 수 있어요.

GeoJoin의 특징:

- 지리 공간 함수를 사용하는 테이블 조인 쿼리를 자동으로 최적화해요.
- 지리 데이터셋 사이의 공간 중첩(spatial overlap) 분석을 수행해요.

GeoJoin 최적화는 Snowflake의 쿼리 최적화 프로그램이 SQL 쿼리에서 적절한 지리 공간 조인 패턴을 감지하면 자동으로 트리거돼요. 개선된 성능을 누리기 위한 추가 구성은 필요 없어요.

#### GEOMETRY 술어에 대한 지리 공간 가지치기

Snowflake는 일치하는 행을 포함할 수 없는 [마이크로파티션을 가지치기(pruning)](</user-guide/tables-clustering-micropartitions#label-micropartitions-query-pruning>)함으로써 GEOMETRY 컬럼에서 필터링하는 일부 쿼리의 성능을 개선할 수 있어요. 이 최적화는 GEOMETRY 값과 함께 저장된 경계 상자(bounding-box) 메타데이터를 사용해 술어를 충족시키지 못할 것이 보장되는 데이터를 스캔하지 않도록 해요. 즉 Snowflake는 필터의 상수 지오메트리의 경계 상자와 겹치지 않는 경계 상자 메타데이터가 저장된 마이크로파티션을 건너뛰어요.

Snowflake는 이 최적화를 자동으로 수행하며, 개선된 성능을 누리기 위한 추가 구성은 필요 없어요.

##### 지리 공간 가지치기의 혜택을 받을 수 있는 술어

가지치기는 한쪽이 상수 지오메트리(리터럴이나 상수 접힘이 가능한 표현식 같은)인 GEOMETRY 컬럼의 필터 술어를 위해 설계됐어요. 예를 들어:

- `ST_INTERSECTS(geom_col, <constant_geometry>)`
- `ST_CONTAINS(geom_col, <constant_geometry>)`
- `ST_COVERS(geom_col, <constant_geometry>)`
- `ST_COVEREDBY(geom_col, <constant_geometry>)`
- `ST_WITHIN(geom_col, <constant_geometry>)`

이것들은 경계 상자를 사용하는 파일 수준 가지치기의 혜택을 받는 특정 술어 유형이에요.

##### 지리 공간 가지치기의 작동 방식

GEOMETRY 값은 다음 항목을 포함한 메타데이터와 함께 저장돼요.

- 경계 상자 (xmin, ymin, xmax, ymax)
- SRID 값

Snowflake는 파일 수준 경계 상자 메타데이터를 가지치기의 주요 신호로 사용해요.

Snowflake는 정확한 지오메트리 술어를 평가하기 전에 마이크로파티션의 경계 상자 교차를 사전 점검해요. 메타데이터가 경계 상자 중첩이 불가능함을 나타내면 그 마이크로파티션들을 건너뛸 수 있어요.

다음 그림은 두 개의 교차 형상과 두 개의 비교차 형상이 있는 경계 상자 선을 보여 줘요.

이 그림은 다음 예제와 유사한 지리 공간 쿼리를 보여 줘요.

SELECT * FROM

WHERE ST_CONTAINS(<geo_column>, <constant_geometry>);


지리 공간 상수에서 지정된 경계 상자(파란색 표시)에 대해, 경계 상자 선과 겹치는 경계 상자에 해당하는 마이크로파티션(녹색 표시)만 스캔돼요. 겹치지 않는 경계 상자에 해당하는 마이크로파티션(빨간색 표시)은 가지치기돼요.

##### SRID 동작

Snowflake의 공간 술어는 SRID에 민감해요. 따라서 같은 컬럼에서 호환되지 않는 SRID를 섞으면 잘못된 결과가 반환될 수 있어요. 최상의 결과와 결정적 동작을 위해 GEOMETRY 컬럼 안에서 SRID를 일관되게 유지하는 것이 좋아요. 이는 일반적인 실제 패턴이기도 해요.

##### Iceberg 테이블에 대한 지리 공간 가지치기

Iceberg GEOMETRY 컬럼의 경우 Snowflake는 표준 Snowflake 테이블의 GEOMETRY 컬럼과 같은 방식으로 지리 공간 가지치기에 경계 상자 메타데이터를 사용하려 해요. 기본 Iceberg 메타데이터에 필요한 통계가 있으면 같은 가지치기 로직이 수정 없이 적용돼요.

##### 지리 공간 가지치기에 대한 다른 성능 고려 사항

지리 공간 가지치기는 데이터 배치가 Snowflake가 큰 범위의 마이크로파티션을 건너뛰도록 할 때 가장 잘 동작해요. 비슷한 위치의 행이 많은 마이크로파티션에 퍼져 있으면, 가지치기를 사용해도 Snowflake가 테이블의 큰 부분을 스캔해야 할 수 있어요.

위치별 클러스터링은 가지치기 효율을 개선할 수 있어요. GEOMETRY 컬럼에서 파생된 공간 키로 행을 클러스터링하면 서로 가까운 객체들이 같은 마이크로파티션에 저장될 가능성이 높아져요. 결과적으로 상수 지오메트리가 있는 ST_INTERSECTS나 ST_CONTAINS 같은 공간 필터가 더 많은 마이크로파티션을 가지치고 더 적은 데이터를 읽을 수 있어요.

지리 공간 가지치기를 최적화하려면 다음 모범 사례를 따라요.

- 지오메트리의 대표점(예: 중심점)에서 계산한 이산화된 공간 인덱스(H3나 geohash 같은)로 클러스터링해요. 쿼리 창 크기에 적합한 해상도를 사용해요.
- 지오메트리가 크면(넓은 영역을 덮는 다각형 같은) 여러 키로 클러스터링해 과도한 클러스터링(over-clustering)을 줄이고 선택성을 개선해요. 예를 들어 두 해상도의 H3로 또는 조밀한 그리드 키와 더 미세한 그리드 키로 클러스터링해요. 지배적인 쿼리 패턴("도시 내"나 "타일 내" 같은)이 있는 데이터셋의 경우 그 패턴에 맞는 클러스터링 키를 선택해요.

다음 예제는 점을 포함하는 GEOMETRY 컬럼으로 테이블을 클러스터링해요.

ALTER TABLE <table_name> CLUSTER BY (H3_POINT_TO_CELL(<geo_column>, <h3_resolution>));


다음 예제는 LineString과 Polygon을 포함하는 GEOMETRY 컬럼으로 테이블을 클러스터링해요.

ALTER TABLE <table_name> CLUSTER BY (H3_POINT_TO_CELL(ST_CENTROID(<geo_column>), <h3_resolution>));


**Note**

- 클러스터링은 쿼리 결과를 바꾸지 않아요. 저장에서 데이터가 조직되는 방식을 바꿔요. 클러스터링의 이점은 데이터 분포, 테이블 크기, 쿼리 패턴에 따라 달라져요.
- 클러스터링 전후의 스캔된 바이트와 스캔된 마이크로파티션을 비교해 가지치기 효율을 모니터링할 수 있어요.

##### 지리 공간 가지치기의 제한 사항

지리 공간 가지치기에는 다음 제한 사항이 적용돼요.

- GEOMETRY(평면) 술어에만 적용돼요.

GEOGRAPHY 술어를 가지치려면 [검색 최적화](</user-guide/search-optimization-service>)를 사용해요.

- 술어 인자 하나가 상수일 때만 적용돼요.

두 술어 인자가 모두 컬럼이면(예: `ST_INTERSECTS(a.geom, b.geom)`) 이 최적화가 적용되지 않아요. 이런 경우 GeoJoin이 사용될 수 있어요.

### 유효하지 않은 지리 공간 형상 처리 방법 지정

기본적으로 [지리 공간 변환 함수](</sql-reference/functions-geospatial>)로 지원되는 입력 포맷의 데이터를 GEOGRAPHY 또는 GEOMETRY 객체로 변환할 때, 함수는 다음을 수행해요.

1. 입력 데이터의 형상을 검증하려 시도해요.
2. [Open Geospatial Consortium의 Simple Feature Access / Common Architecture](<https://www.ogc.org/standards/sfa>) 표준에 따라 형상이 유효한지 결정해요.
3. 형상이 유효하지 않으면 데이터를 복구하려 시도해요(예: 링을 닫아 다각형 수정).
4. 복구 후에도 형상이 여전히 유효하지 않으면 오류를 보고하고 GEOGRAPHY 또는 GEOMETRY 객체를 만들지 않아요. (TRY_* 함수의 경우 오류를 보고하지 않고 NULL을 반환해요.)

이 기능으로 검증과 복구 과정을 더 잘 제어할 수 있어요. 다음을 할 수 있어요.

- 이 변환 함수들이 유효하지 않은 형상에 대한 GEOGRAPHY·GEOMETRY 객체를 만들도록 허용.
- GEOGRAPHY 또는 GEOMETRY 객체의 형상이 유효하지 않은지 확인.

#### 유효하지 않은 형상이 지리 공간 함수에 미치는 영향 이해

유효하지 않은 형상에 대한 GEOGRAPHY 또는 GEOMETRY 객체를 전달할 때 [지리 공간 함수](</sql-reference/functions-geospatial>)마다 영향이 달라요.

##### GEOMETRY 객체에 대한 영향

GEOMETRY 객체의 경우:

- 다음 함수들은 원래의 유효하지 않은 형상을 기반으로 결과를 반환해요:
  - [ST_AREA](</sql-reference/functions/st_area>)
  - [ST_ASGEOJSON](</sql-reference/functions/st_asgeojson>)
  - [ST_ASWKB](</sql-reference/functions/st_aswkb>)
  - [ST_ASWKT](</sql-reference/functions/st_aswkt>)
  - [ST_CENTROID](</sql-reference/functions/st_centroid>)
  - [ST_CONTAINS](</sql-reference/functions/st_contains>)
  - [ST_DIMENSION](</sql-reference/functions/st_dimension>)
  - [ST_DISTANCE](</sql-reference/functions/st_distance>)
  - [ST_ENVELOPE](</sql-reference/functions/st_envelope>)
  - [ST_INTERSECTS](</sql-reference/functions/st_intersects>)
  - [ST_LENGTH](</sql-reference/functions/st_length>)
  - [ST_NPOINTS , ST_NUMPOINTS](</sql-reference/functions/st_npoints>)
  - [ST_PERIMETER](</sql-reference/functions/st_perimeter>)
  - [ST_SETSRID](</sql-reference/functions/st_setsrid>)
  - [ST_SRID](</sql-reference/functions/st_srid>)
  - [ST_X](</sql-reference/functions/st_x>)
  - [ST_XMAX](</sql-reference/functions/st_xmax>)
  - [ST_XMIN](</sql-reference/functions/st_xmin>)
  - [ST_Y](</sql-reference/functions/st_y>)
  - [ST_YMAX](</sql-reference/functions/st_ymax>)
  - [ST_YMIN](</sql-reference/functions/st_ymin>)
- 다음 함수들은 형상을 검증하고 형상이 유효하지 않으면 오류로 실패해요:
  - [ST_MAKELINE](</sql-reference/functions/st_makeline>)
  - [ST_MAKEPOLYGON](</sql-reference/functions/st_makepolygon>)

##### GEOGRAPHY 객체에 대한 영향

GEOGRAPHY 객체의 경우:

- 다음 함수들은 원래의 유효하지 않은 형상을 기반으로 결과를 반환해요:
  - [ST_ASWKB](</sql-reference/functions/st_aswkb>)
  - [ST_ASWKT](</sql-reference/functions/st_aswkt>)
  - [ST_ASGEOJSON](</sql-reference/functions/st_asgeojson>)
  - [ST_AZIMUTH](</sql-reference/functions/st_azimuth>)
  - [ST_COLLECT](</sql-reference/functions/st_collect>)
  - [ST_DIMENSION](</sql-reference/functions/st_dimension>)
  - [ST_GEOHASH](</sql-reference/functions/st_geohash>)
  - [ST_HAUSDORFFDISTANCE](</sql-reference/functions/st_hausdorffdistance>)
  - [ST_MAKELINE](</sql-reference/functions/st_makeline>)
  - [ST_NPOINTS , ST_NUMPOINTS](</sql-reference/functions/st_npoints>)
  - [ST_POINTN](</sql-reference/functions/st_pointn>)
  - [ST_SRID](</sql-reference/functions/st_srid>)
  - [ST_ENDPOINT](</sql-reference/functions/st_endpoint>)
  - [ST_STARTPOINT](</sql-reference/functions/st_startpoint>)
  - [ST_X](</sql-reference/functions/st_x>)
  - [ST_Y](</sql-reference/functions/st_y>)
- 다음 함수들은 형상을 검증하고 형상이 유효하지 않으면 오류로 실패해요:
  - [ST_COLLECT](</sql-reference/functions/st_collect>)
  - [ST_MAKEPOLYGON](</sql-reference/functions/st_makepolygon>)
  - [ST_MAKEPOLYGONORIENTED](</sql-reference/functions/st_makepolygonoriented>)
- 다음 함수들은 값을 계산할 수 없으면 NULL을 반환해요:
  - [ST_AREA](</sql-reference/functions/st_area>)
  - [ST_CENTROID](</sql-reference/functions/st_centroid>)
  - [ST_CONTAINS](</sql-reference/functions/st_contains>)
  - [ST_COVERS](</sql-reference/functions/st_covers>)
  - [ST_DIFFERENCE](</sql-reference/functions/st_difference>)
  - [ST_DISTANCE](</sql-reference/functions/st_distance>)
  - [ST_DWITHIN](</sql-reference/functions/st_dwithin>)
  - [ST_ENVELOPE](</sql-reference/functions/st_envelope>)
  - [ST_INTERSECTION](</sql-reference/functions/st_intersection>)
  - [ST_INTERSECTION_AGG](</sql-reference/functions/st_intersection_agg>)
  - [ST_INTERSECTS](</sql-reference/functions/st_intersects>)
  - [ST_LENGTH](</sql-reference/functions/st_length>)
  - [ST_PERIMETER](</sql-reference/functions/st_perimeter>)
  - [ST_SIMPLIFY](</sql-reference/functions/st_simplify>)
  - [ST_SYMDIFFERENCE](</sql-reference/functions/st_symdifference>)
  - [ST_UNION](</sql-reference/functions/st_union>)
  - [ST_UNION_AGG](</sql-reference/functions/st_union_agg>)
  - [ST_XMAX](</sql-reference/functions/st_xmax>)
  - [ST_XMIN](</sql-reference/functions/st_xmin>)
  - [ST_YMAX](</sql-reference/functions/st_ymax>)
  - [ST_YMIN](</sql-reference/functions/st_ymin>)

#### 유효하지 않은 형상 작업

다음 섹션들은 함수가 유효하지 않은 형상을 만들도록 허용하는 방법과, GEOGRAPHY 또는 GEOMETRY 객체가 유효하지 않거나 복구된 형상을 나타내는지 확인하는 방법을 설명해요.

##### 변환 함수가 유효하지 않은 형상을 만들도록 허용

다음 변환 함수가 유효하지 않은 지리 공간 객체를 만들도록 허용하려면 두 번째 인자(`_allowInvalid_`)에 `TRUE`를 전달해요.

TO_GEOGRAPHY( [, ] )


ST_GEOGFROMWKB( [, ] )


ST_GEOGFROMWKT( [, ] )


TO_GEOMETRY( [, ] )


ST_GEOMFROMWKB( [, ] )


ST_GEOMFROMWKT( [, ] )


기본적으로 `_allowInvalid_` 인자는 `FALSE`예요.

`_allowInvalid_` 인자에 `TRUE`를 전달하면, 입력 형상이 유효하지 않고 성공적으로 복구될 수 없더라도 변환 함수가 GEOGRAPHY 또는 GEOMETRY 객체를 반환해요.

예를 들어 다음 입력 형상은 같은 두 Point로 구성된 LineString이에요. `_allowInvalid_` 인자에 `TRUE`를 전달하면 유효하지 않은 형상을 나타내는 GEOMETRY 객체를 반환해요.

SELECT TO_GEOMETRY('LINESTRING(100 102,100 102)', TRUE);


##### 형상이 유효하지 않은지 확인

GEOGRAPHY 또는 GEOMETRY 객체가 유효하지 않은지 확인하려면 [ST_ISVALID](</sql-reference/functions/st_isvalid>) 함수를 호출해요.

다음 예제는 객체가 유효한지 확인해요.

SELECT TO_GEOMETRY('LINESTRING(100 102,100 102)', TRUE) AS g, ST_ISVALID(g);


## 더 알아보기 (Learn more)

- [지리 공간 함수](</sql-reference/functions-geospatial>) — GEOGRAPHY·GEOMETRY 연산 함수 목록
- [날짜·시간 데이터 타입](</sql-reference/data-types-datetime>) — 날짜와 시간 타입
- [데이터 타입 변환](</sql-reference/data-type-conversion>) — 타입 간 변환 규칙
- [검색 최적화 서비스](</user-guide/search-optimization-service>) — 지리 공간 쿼리 성능 개선