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_ 函数,如 ST_Distance/ST_DWithin/ST_Intersects/ST_Contains。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 提供两种空间类型: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 给出两点间的距离。这是核心功能,无需模块。

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 中打开 →