Работа с геоданными: PostGIS, MySQL Spatial, Geography и Geometry

Почему геоданные — это круто? 🌍

Представь: ты можешь находить все кафе в радиусе 500 метров от офиса, строить оптимальные маршруты доставки или анализировать зоны покрытия сотовой сети. Всё это — геоданные! А теперь давай научимся с ними работать.


PostGIS vs MySQL Spatial: в чём разница?

PostGIS — расширение для PostgreSQL, которое превращает его в мощную гео-СУБД. Поддерживает:

  • Все типы геоданных (Point, LineString, Polygon и др.)
  • Пространственные индексы (GIST)
  • Сотни функций: ST_Distance, ST_Contains, ST_Intersects
-- Пример в PostGIS
SELECT name 
FROM coffee_shops
WHERE ST_DWithin(
  location,
  ST_MakePoint(37.6178, 55.7512),  -- Координаты Кремля
  500  -- Радиус в метрах
);

MySQL Spatial — встроенный функционал MySQL, но с ограничениями:

  • Нет типа geography (только geometry)
  • Меньше функций (но базовые есть)
  • Работает в метрической системе (не учитывает сферу Земли)
-- Пример в MySQL
SELECT name 
FROM coffee_shops
WHERE ST_Distance_Sphere(
  location,
  ST_GeomFromText('POINT(37.6178 55.7512)')
) <= 500;

👉 Вывод: PostGIS — для сложных задач, MySQL Spatial — для простых.


Geography vs Geometry: битва типов 🥊

Geometry (плоская система)

  • Работает в 2D/3D пространстве
  • Быстрые вычисления (евклидова геометрия)
  • Идеально для карт небольших территорий
-- Расстояние между двумя точками в Geometry (в градусах!)
SELECT ST_Distance(
  ST_GeomFromText('POINT(0 0)'),
  ST_GeomFromText('POINT(1 1)')
);

Geography (эллипсоидная система)

  • Учитывает кривизну Земли
  • Координаты в градусах (WGS84)
  • Точнее для глобальных расчетов
-- Расстояние между Москвой и Санкт-Петербургом (в метрах!)
SELECT ST_Distance(
  ST_GeographyFromText('POINT(37.6178 55.7512)'),  -- Москва
  ST_GeographyFromText('POINT(30.3159 59.9391)')   -- СПб
);

🔍 Важно: В PostGIS можно использовать оба типа, в MySQL — только Geometry.


Практика: строим геозапросы 🛠️

1. Поиск объектов в радиусе

-- PostGIS: Кафе в 1 км от точки
SELECT name, ST_AsText(location) AS coords
FROM places
WHERE ST_DWithin(
  location::geography,
  ST_MakePoint(37.6178, 55.7512)::geography,
  1000
);

2. Пересечение полигонов

-- MySQL: Найти районы, пересекающиеся с парком
SELECT districts.name
FROM districts, parks
WHERE ST_Intersects(
  districts.geom,
  parks.geom
)
AND parks.name = 'Центральный парк';

3. Построение маршрута

-- PostGIS: Соединяем точки линией
SELECT ST_MakeLine(
  ST_Point(0, 0),
  ST_Point(1, 1),
  ST_Point(1, 2)
) AS route;

Оптимизация: пространственные индексы 🚀

Без индексов геозапросы тормозят. Решение — GIST (в PostGIS) или SPATIAL (в MySQL):

-- PostGIS
CREATE INDEX idx_places_geo ON places USING GIST(location);

-- MySQL
CREATE SPATIAL INDEX idx_places_geo ON places(location);

💡 Правило: Индексируй поля, по которым часто ищешь (ST_Distance, ST_Contains).


Где применять эти знания? 🗺️

  1. Логистика: оптимизация маршрутов доставки
  2. Ритейл: анализ зон покрытия магазинов
  3. Недвижимость: поиск объектов в нужном районе
  4. IoT: трекинг устройств с GPS

Попробуй прямо сейчас — создай базу с геоданными и сделай свой первый пространственный запрос! Координаты твоего успеха уже определены. 😉

Скрыть рекламу навсегда

🎥 YouTube: программирование простым языком

Канал, где я спокойно и по шагам объясняю сложные темы — без заумных терминов и лишней теории.

Подходит, если раньше «не заходило», но хочется наконец понять.

▶️ Смотреть курсы на YouTube