DBAtlas · データベース運用アトラス

地理/空間クエリ

Oracle

-- Oracle Spatial: SDO_GEOMETRY column and spatial index
CREATE INDEX location_sidx ON shop(location)
  INDEXTYPE IS MDSYS.SPATIAL_INDEX;
-- Shops within 5 km:
SELECT name FROM shop
WHERE SDO_WITHIN_DISTANCE(location,
  SDO_GEOMETRY(2001, 4326,
    SDO_POINT_TYPE(32.85, 39.92, NULL), NULL, NULL),
  'distance=5 unit=KM') = 'TRUE';

Oracle Spatial は地理データを SDO_GEOMETRY 型で格納する。USER_SDO_GEOM_METADATA のエントリと空間インデックスが必要。SDO_WITHIN_DISTANCE、SDO_RELATE、SDO_NN などの演算子が距離/交差/最近傍のクエリに対応する。SRID 4326 は WGS84(緯度/経度)系。

PostgreSQL

-- PostGIS extension:
CREATE EXTENSION IF NOT EXISTS postgis;
CREATE INDEX location_gix ON shop USING GIST (location);
-- Shops within 5 km (geography, meters):
SELECT name FROM shop
WHERE ST_DWithin(location,
  ST_SetSRID(ST_MakePoint(32.85, 39.92), 4326)::geography,
  5000);

PostGIS は PostgreSQL をフル機能の空間データベースにする。geometry(平面)と geography(球面)の型、および ST_Distance/ST_DWithin/ST_Intersects/ST_Contains などの数百の ST_ 関数を提供する。GiST/SP-GiST インデックスが空間クエリを高速化する。

MySQL

-- Spatial column (with SRID) and SPATIAL index:
ALTER TABLE shop MODIFY location POINT NOT NULL SRID 4326;
ALTER TABLE shop ADD SPATIAL INDEX (location);
-- Compute distance (meters, geography):
SELECT name,
  ST_Distance(location,
    ST_SRID(POINT(32.85, 39.92), 4326)) AS distance
FROM shop
ORDER BY distance LIMIT 10;

MySQL(5.7+)は OGC 準拠の空間データ型(POINT、POLYGON など)と ST_ 関数をサポートする。SPATIAL インデックス(R-tree)は InnoDB/MyISAM の NOT NULL 列にのみ作成できる。オプティマイザが使用するには、列を SRID 属性(SRID 4326)付きで定義する必要がある。SRID 4326 では ST_Distance はメートル単位の測地距離を返す。POINT(x, y) + ST_SRID では x が経度、y が緯度。SRID 4326 の WKT 入力(ST_GeomFromText)では順序は緯度-経度。

SQL Server

-- geography type and spatial index:
CREATE SPATIAL INDEX location_sidx ON dbo.shop(location);
-- Shops within 5 km (STDistance returns meters):
SELECT name FROM dbo.shop
WHERE location.STDistance(
  geography::Point(39.92, 32.85, 4326)) <= 5000;

SQL Server は 2 つの空間型を提供する: geography(球面、緯度/経度)と geometry(平面)。STDistance、STIntersects、STContains などのメソッドがクエリに対応する。空間インデックス(グリッドベース)が性能を向上させる。geography::Point(latitude, longitude, SRID) の引数の順序に注意する。

MongoDB

// 2dsphere index (for GeoJSON):
db.shop.createIndex({ location: "2dsphere" })
// Shops nearest to a given point ($near):
db.shop.find({
  location: {
    $near: {
      $geometry: { type: "Point", coordinates: [32.85, 39.92] },
      $maxDistance: 5000
    }
  }
})

MongoDB は地理データを GeoJSON 形式で格納し、2dsphere インデックスで球面クエリを実行する。$near(距離順)、$geoWithin(領域内)、$geoIntersects 演算子がサポートされる。座標は [経度, 緯度] の順で、$maxDistance はメートル単位。

Redis

# Built-in geospatial commands (built on sorted sets):
GEOADD shops 32.85 39.92 "kizilay"
GEOADD shops 32.86 39.93 "cankaya"
# Search within 5 km of a point:
GEOSEARCH shops FROMLONLAT 32.85 39.92
  BYRADIUS 5 km ASC

Redis は GEOADD(longitude latitude member)で地理的位置を Sorted Set に格納する。GEOSEARCH(Redis 6.2+、旧 GEORADIUS の後継)は半径またはボックス内のメンバーを距離順に返す。GEODIST は 2 点間の距離を返す。これはコア機能であり、モジュールは不要。

Elasticsearch

# Map the field as geo_point:
PUT shop
{ "mappings": { "properties": { "location": { "type": "geo_point" } } } }
# Query within 5 km:
GET shop/_search
{ "query": { "geo_distance": {
  "distance": "5km",
  "location": { "lat": 39.92, "lon": 32.85 } } } }

Elasticsearch は geo_point(点)と geo_shape(ポリゴン/線)のフィールド型をサポートする。フィルタリングは geo_distance(半径)、geo_bounding_box(ボックス)、geo_polygon クエリで、ソートは geo_distance で、集計は geohash_grid/geotile_grid で行う。座標は lat/lon または [lon, lat] 配列で指定する。

DBAtlas で開く →