
PostgreSQL известна как надежная и универсальная СУБД. Но если нужно хранить координаты, строить маршруты или анализировать границы районов, ее базовых возможностей уже не хватает. Здесь на помощь приходит PostGIS. В тексте разберемся, что умеет расширение и как его использовать.

Selectel Tech Day — 8 октября
Разберем реальный опыт IT-команд, технический бэкстейдж и ML без спецэффектов. 15 стендов и интерактивных зон, доклады, мастер-классы, вечерняя программа и нетворкинг. Участие бесплатное: нужна только регистрация.
Используйте навигацию, если не хотите читать текст целиком:
Что такое PostGIS и зачем его использовать
PostGIS — это расширение с открытым исходным кодом, которое «учит» базу данных работать с геоданными: координатами, линиями, полигонами и другими объектами на карте. С ним можно не просто хранить координаты, но и задавать вопросы: «Что находится рядом?», «Входит ли объект в зону?», «Где пересекаются границы?». Благодаря PostGIS становится удобнее работать с пространственными данными и анализировать их, используя только базу данных.
Для чего использовать PostGIS
Рассмотрим основные сценарии, в которых можно использовать расширение.
Хранение географических данных: точки, линии, полигоны и мультиобъекты (набор данных).
Поиск по пространству (например, обнаружение объектов в радиусе).
Расчет расстояний и построение маршрутов с учетом ограничений (скорость, закрытые участки, особые условия и т. д.).
Анализ пересекающихся областей и границ.
Подобные задачи встречаются в разных сферах: от картографических веб-приложений и систем навигации до управления недвижимостью и городского планирования.
Какие типы данных добавляет PostGIS в PostgreSQL
В первую очередь PostGIS расширяет PostgreSQL благодаря поддержке новых типов данных. Изучим ключевые из них подробнее.
Геометрический (geometry): point, line, polygon, multipoint, multiline, multipolygon, geometrycollections. Подходит для работ в небольшой географической области, где не важен учет географической кривизны.

Географический (geography) — аналог geometry, но с учетом кривизны Земли. Этот тип удобно использовать для расчетов на больших областях.

Растровый (raster) — это способ хранить снимки или карты, где данные закодированы в виде пикселей. Каждый пиксель хранит не просто цвет, а конкретное значение: температуру, высоту над уровнем моря, уровень загрязнения воздуха и т. д.
Помимо новых типов данных PostGIS поддерживает топологическую (topology) модель хранения. При ее использовании база знает не только о форме объектов, но и об их связи друг с другом. Когда мы храним данные в geometry, каждый объект — это самостоятельный рисунок. Например, если есть два соседних района, то их границы будут храниться дважды — один раз у первого района и один раз у второго. Даже если это одна и та же линия. При использовании топологии граница сохраняется один раз, а районы просто ссылаются на нее.
Основные запросы с использованием PostGIS
Мы разобрались в типах данных, которые добавляет PostGIS. Теперь посмотрим на примеры запросов и узнаем, как работать с геоданными на практике.
Расстояние между объектами
Частая задача — узнать, как далеко находятся два объекта: магазин и клиент, склад и точка доставки, парк и ближайшая станция метро.
-- Считаем расстояние между двумя точками (в градусах)
SELECT ST_Distance(
ST_GeomFromText('POINT(30 10)', 4326), -- первая точка ST_GeomFromText('POINT(40 20)', 4326) -- вторая точка
) AS distance; -- название колонки результата
ST_Distance(geomA, geomB)
— позволяет узнать, как далеко объекты друг от друга.ST_GeomFromText
— преобразует текстовое представление геометрии в объект базы данных.4326
— это EPSG-код системы координат.
EPSG — международный стандарт для описания проекций и систем координат.
Пересечение объектов
Допустим, вам нужно проверить пересечение объектов — например, не проходит ли маршрут через запретную зону или не попадает ли район в охраняемую территорию.
-- Находим все полигоны, которые пересекаются с заданным объектом
SELECT name
FROM parks -- таблица, в которой хранятся полигоны парков (geom) и их названия (name)
WHERE ST_Intersects(
geom, -- геометрия полигона из таблицы parks
ST_GeomFromText('POLYGON((30 10, 40 40, 20 40, 10 20, 30 10))', 4326) -- преобразует текстовый полигон в объект geometry
);
Функция ST_Intersects(geomA, geomB)
проверяет, где объекты «накладываются» друг на друга и возвращает логическое значение TRUE, если они пересекаются.
Проверка, входит ли объект в область
Задача: определить, находится ли дом внутри конкретного района или точка доставки в пределах зоны обслуживания.
-- Проверяем, находится ли точка внутри полигона
SELECT ST_Within(
ST_GeomFromText('POLYGON((30 10, 40 40, 20 40, 10 20, 30 10))', 4326),
ST_GeomFromText('POINT(25 25)', 4326)
) AS is_inside; -- наименование столбца, в котором будет результат
Функция ST_Within(geomA, geomB)
возвращает TRUE, если объект B полностью находится внутри полигона А.
Объединение нескольких объектов в мультиполигон
Такой подход пригодится, например, для объединения районов в общий контур города.
-- Объединяем несколько полигонов в один объект
SELECT ST_Union(geom) AS multi_geom -- объединяет все выбранные геометрии (geom) в один объект
FROM districts
WHERE city = 'SPb';
ST_Union
собирает несколько полигонов в один. Например, можно объединить районы в общий полигон — город.
Получение координат объекта
Пригодится, когда нужно посмотреть, как геометрия хранится на «человеческом языке».
-- Извлекаем координаты точки
SELECT ST_AsText(geom) AS coordinates
FROM stores
WHERE name = 'SuperMart';
ST_AsText(geom)
показывает координаты в виде привычного текста — например, POINT(30 10)
.
Поиск площади области
Пригодится, когда требуется рассчитать площадь территории: парка, района или земельного участка.
-- Считаем площадь полигона (в квадратных метрах)
SELECT ST_Area(geom::geography) AS area_m2 -- преобразует объект geometry в текстовое представление WKT - POINT(30 10)
FROM parks
WHERE name = 'Central Park';
Функция ST_Area(geom)
возвращает площадь полигона. При этом приведение к geography учитывает кривизну Земли и дает результат в м².
WKT (Well-Known Text) — это текстовый формат описания геометрических объектов.
Поиск объектов, присутствующих в выделенной области
Например, нам нужно найти все здания, попадающие внутрь выделенного полигона.
-- Ищем все здания внутри заданного полигона
SELECT name
FROM buildings
WHERE ST_Within(
geom,
ST_GeomFromText('POLYGON((30 10, 40 40, 20 40, 10 20, 30 10))', 4326)
);
ST_Within
возвращает объекты, которые полностью находятся внутри заданной области. Возвращает TRUE
, если объект полностью внутри, и FALSE
, если хотя бы часть объекта выходит за границы полигона.
Дополнительные функции PostGIS (шпаргалка)
PostGIS закрывает десятки типовых задач при работе с геоданными. Ниже — шпаргалка по основным функциям, сгруппированным по типам данных. Такой список удобно использовать как справочник: быстро вспомнить синтаксис или подобрать нужную операцию.
Тип данных |
Функции и возможности |
Описание |
Geometry. Работа с объектами на плоскости: точки, линии, полигоны |
|
Возвращает область пересечения двух объектов |
|
Объединяет несколько геометрий в одну |
|
|
Вычитает один объект из другого |
|
|
Находит центр объекта (центроид) |
|
|
Длина линии или периметр полигона |
|
|
Площадь полигона |
|
|
Проверяет, содержит ли объект другой |
|
|
Проверяет, находится ли объект внутри другого |
|
|
Проверяет, соприкасаются ли объекты |
|
|
Проверяет частичное перекрытие объектов |
|
|
Возвращает внешний контур полигона |
|
|
Количество точек в геометрии |
|
Geography. Расчеты на поверхности Земли с учетом кривизны |
|
Расстояние между объектами |
|
Длина линии по поверхности Земли |
|
|
Азимут между двумя точками |
|
|
Зона влияния |
|
|
Ближайшая точка одного объекта к другому |
|
|
Получает новую точку по направлению и расстоянию |
|
|
Площадь объекта |
|
|
Проверяет, находятся ли объекты на расстоянии меньше заданного |
|
Raster. Операции с растровыми данными (например, спутниковыми снимками) |
|
Применяет формулы ко всем пикселям |
|
Вырезает часть растрового слоя по полигону |
|
|
Изменяет разрешение растрового изображения |
|
|
Считает статистику по растровым данным (среднее, min, max) |
|
|
Возвращает значение пикселя по координатам |
|
|
Вычисляет угол наклона поверхности (полезно для рельефа) |
|
Topology. Работа с топологическими сетями: узлы, ребра, границы |
|
Получает все узлы топологической сети |
|
Получает линии между узлами |
|
|
Возвращает области, образованные смежными границами |
|
|
Обновляет топологию при изменении объекта |
|
|
Проверяет корректность топологической модели |
|
S |
Получает смежные полигоны для заданного полигона |
|
|
Возвращает площадь топологического полигона |
|
|
Возвращает узлы, соединенные ребром топологии |
Как развернуть БД PostgreSQL с PostGIS в Selectel
Оптимальная конфигурация PostgreSQL для работы с геоданными
В Selectel доступны несколько линеек конфигураций. Каждая — с разным соотношением ресурсов: vCPU, RAM и локального диска. Для задач с PostGIS, когда нужно обрабатывать растровые данные или сложные топологические вычисления, рекомендуем линейки HighFreq или CPU.
HighFreq — высокая производительность CPU и SSD NVMe-диски повышенной производительности. Подходит для вычислительных операций и сложной аналитики.
CPU — оптимальный баланс производительности для умеренных нагрузок..
Для работы с геоданными важны мощный процессор и достаточный объем памяти — это ускоряет построение индексов, выполнение пространственных запросов и обработку растров. А NVMe-диск дополнительно повышает скорость операций с большими массивами данных.
Если нагрузка стабильная и предсказуемая, можно выбрать линейку Standard. Но для начала лучше взять HighFreq или CPU — они предоставят запас по производительности.
Почему важны индексы
Индекс — это вспомогательная структура в базе данных, которая хранит информацию о расположении данных в таблице. Она позволяет быстро находить нужные строки без полного перебора всех записей.
В PostGIS используются пространственные индексы — они позволяют работать с полигонами, линиями и точками без полного сканирования таблицы. База данных хранит их в виде пространственных структур (GiST, SP-GiST, BRIN), благодаря чему запросы вроде ST_Intersects
или ST_DWithin
выполняются за миллисекунды даже на больших таблицах. Подробнее об индексах — в официальной документации PostgreSQL.
Разворачиваем кластер и включаем PostGIS
1. В панели управления в верхнем меню открываем Продукты → Облачные базы данных.

2. Нажимаем кнопку Создать кластер.

3. Выбираем имя кластера, версию PostgreSQL 17 и конфигурацию ноды. В нашем случае — HighFreq: 2 vCPU, 8 ГБ RAM, 64 ГБ. Далее для создания кластера нажимаем кнопку Создать кластер. Он будет готов к работе, когда перейдет в статус ACTIVE.

Со всеми деталями вы можете ознакомиться в документации по созданию кластера PostgreSQL.
4. Заходим в карточку кластера. Для этого нужно нажать на имя, которое мы ему присвоили. Переходим на вкладку Пользователи и нажимаем Создать пользователя.

5. Выбираем имя пользователя, через кнопку Сгенерировать генерируем надежный пароль и нажимаем кнопку Создать.
6. Переходим во вкладку Базы данных и нажимаем Создать базу данных.

7. Указываем имя для БД, владельцем выбираем созданного пользователя. LC_CTYPE
и LC_COLLATE
выбираем en_US.utf8
— это универсальная локаль для проектов на английском и поддержкой юникода (UTF-8). Нажимаем кнопку Создать.

8. Раскрываем настройки БД и выбираем пользователей, которые будут обладать доступом к ней. Также добавляем расширения: postgis
, postgis_raster
, postgis_topology
.

9. Подключаемся к БД. Информацию по подключению вы можете найти на вкладке Подключение или в документации.
10. Проверяем установленные расширения командой \dx
:

Если все необходимые расширения есть, переходим к самому интересному — изучению функций PostGIS.
Работа PostgreSQL с PostGIS
Расстояние между точками
Чтобы получить расстояние в метрах, нужно использовать тип GEOGRAPHY. Он учитывает форму Земли (кривизну) и автоматически возвращает результат в метрах.
SELECT ST_Distance(
ST_GeogFromText('SRID=4326;POINT(30 10)'),
ST_GeogFromText('SRID=4326;POINT(40 20)')
) AS distance_meters;
ST_Distance
— расчет дистанции между объектами.ST_GeogFromText
— преобразование текстового представления в реальный объект типа GEOGRAPHY.SRID=4326
— идентификатор системы координат (Spatial Reference System Identifier, SRID). Он сообщает базе, как интерпретировать значения.4326
соответствует WGS84 — глобальному стандарту, который используют GPS, OpenStreetMap и Google Maps. Координаты в этой системе задаются в градусах широты и долготы.
После выполнения команды получаем результат в метрах:

Также если у вас есть колонка типа GEOMETRY и вы хотите расчитать расстояние в метрах, ее можно временно преобразовать в GEOGRAPHY. Для этого используем приведение типов ::geography. В PostgreSQL и PostGIS :: — это оператор приведения типов (cast), который позволяет изменить тип данных объекта на другой.
SELECT ST_Distance(
ST_GeomFromText('POINT(30 10)', 4326)::geography,
ST_GeomFromText('POINT(40 20)', 4326)::geography
) AS distance_meters;
ST_GeomFromText
— функция PostGIS, которая превращает текстовое описание объекта в реальный объект типа GEOMETRY.
Получаем такой же результат, как и в прошлый раз. Но если убрать оператор приведения ::geography
, то получим результат в градусах, так как geometry — это тип данных в PostGIS для хранения пространственных объектов.

Пересечение полигона и заданного объекта
Рассмотрим функцию ST_Intersects
, которая проверяет, пересекаются ли два пространственных объекта.
SELECT ST_Intersects(
ST_GeomFromText('POLYGON((10 10, 50 10, 50 50, 10 50, 10 10))', 4326),
ST_GeomFromText('LINESTRING(60 60, 70 70, 80 80)', 4326)
) AS does_intersect;
LINESTRING
— это тип данных в PostGIS, который представляет собой линейный объект и состоит из последовательности точек.
Функция возвращает t = true
, если объект попадает внутрь полигона, иначе — f = false
.

Точка внутри полигона
Проверим, входит ли точка в полигон.
SELECT ST_Intersects(
ST_GeomFromText('POLYGON((30 10, 40 40, 20 40, 10 20, 30 10))', 4326),
ST_GeomFromText('POINT(25 25)', 4326)
) AS does_intersect;
Результат: t = true
— точка внутри полигона, f = false
— точка снаружи.

Объединение двух полигонов
Функция ST_Union
помогает объединить полигоны:
SELECT ST_AsText(
ST_Union(
ST_GeomFromText('POLYGON((10 10, 20 10, 20 20, 10 20, 10 10))', 4326),
ST_GeomFromText('POLYGON((15 15, 25 15, 25 25, 15 25, 15 15))', 4326)
)
) AS multi_geom;
Результат — WKT-строка мультиполигона:

Получение координат точки
Используем функцию ST_AsText
:
SELECT ST_AsText(
ST_GeomFromText('POINT(30 10)', 4326)
) AS coordinates;
Вернется строка с координатами точки.

Площадь полигона
Для расчета площади полигона воспользуемся ST_Area
и тип GEOGRAPHY:
.
SELECT ST_Area(
ST_GeogFromText('SRID=4326;POLYGON((30 10, 40 40, 20 40, 10 20, 30 10))')
) AS area_m2;
В результате получаем площадь в квадратных метрах.

Находится ли один объект внутри другого
ST_Within
проверяет, входит ли объект в полигон:
SELECT ST_Within(
ST_GeomFromText('POINT(15 15)', 4326),
ST_GeomFromText('POLYGON((10 10, 20 10, 20 20, 10 20, 10 10))', 4326)
) AS inside_polygon;
Функция возвращает t = true
, если точка внутри полигона. Иначе — f = false
.

Что в итоге
PostGIS предоставляет понятный и удобный способ работы с геоданными: вся информация хранится в единой БД, а доступ к ней осуществляется с помощью привычных SQL-запросов. Не нужно использовать отдельные системы или приложения, конвертировать форматы или вручную рассчитывать расстояния и проверять пересечения. Расширение добавляет поддержку пространственных объектов — от простых точек до сложных полигонов, а также позволяет применять к ним сразу десятки готовых функций.
В результате анализ данных проводится быстрее и с меньшими усилиями. Более того, работа с геоданными становится понятной даже для новичков, ведь изначально взаимодействие с пространственными данными может показаться сложным и запутанным.
Для опытных специалистов расширение позволяет избавиться от рутины и ускорить решение повседневных задач. Теперь можно сконцентрироваться на логике и ценности данных, а не на технических ограничениях.
Akina
GIS - гораздо более применимая система, чем вы описываете. И я считаю, что такого рода статьи категорически НЕ способствуют широкому применению GIS на практике. Причина проста. GIS - это система для работы с двумерными данными. ЛЮБЫМИ двумерными данными. И геоинформация - всего лишь одно из приложений, но далеко не единственное. Работа с графиками, изображениями и пр. - прекрасные места для использования этого расширения. Но вот именно это применение почему-то практически всегда в статьях отсутствует. И зачастую задачи, которые элементарно решаются применением геометрических данных, на практике решаются ну очень заковыристыми методами, потому что программисту в голову не пришло. А не пришло потому, что он не читал и не видел ТАКОГО применения геобиблиотеки, потому что никто не взял себе за труд описать её применение во всех областях, где она по делу, а не только в самой очевидной.
Жаль...
Sleuthhound
Это и не статья о PostGIS, а промо-ролик что у нас в облаке есть PostGIS. Все, что описано в статье есть в документации и перемалывать одно и то же нет смысла.
Реально интересные вещи о PostGIS разве что на конференциях рассказывают.