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.

Работа с объектами на плоскости: точки, линии, полигоны

ST_Intersection(geomA, geomB)

Возвращает область пересечения двух объектов

ST_Union(geomA, geomB)

Объединяет несколько геометрий в одну

ST_Difference(geomA, geomB)

Вычитает один объект из другого

ST_Centroid(geom)

Находит центр объекта (центроид)

ST_Length(geom)

Длина линии или периметр полигона

ST_Area(geom)

Площадь полигона

ST_Contains(geomA, geomB)

Проверяет, содержит ли объект другой

ST_Within(geomA, geomB)

Проверяет, находится ли объект внутри другого

ST_Touches(geomA, geomB)

Проверяет, соприкасаются ли объекты

ST_Overlaps(geomA, geomB)

Проверяет частичное перекрытие объектов

ST_ExteriorRing(polygon)

Возвращает внешний контур полигона

ST_NumPoints(geom)

Количество точек в геометрии

Geography. 

Расчеты на поверхности Земли с учетом кривизны

ST_Distance(geogA, geogB)

Расстояние между объектами

ST_Length(geog)

Длина линии по поверхности Земли

ST_Azimuth(pointA, pointB)

Азимут между двумя точками

ST_Buffer(geog, distance)

Зона влияния

ST_ClosestPoint(geogA, geogB)

Ближайшая точка одного объекта к другому

ST_Project(point, distance, azimuth)

Получает новую точку по направлению и расстоянию

ST_Area(geog)

Площадь объекта

ST_DWithin(geogA, geogB, distance)

Проверяет, находятся ли объекты на расстоянии меньше заданного

Raster. 

Операции с растровыми данными (например, спутниковыми снимками)

ST_MapAlgebra(rast, 'expression')

Применяет формулы ко всем пикселям

ST_Clip(rast, geom)

Вырезает часть растрового слоя по полигону

ST_Resample(rast, scaleX, scaleY)

Изменяет разрешение растрового изображения

ST_SummaryStats(rast)

Считает статистику по растровым данным (среднее, min, max)

ST_Value(rast, x, y)

Возвращает значение пикселя по координатам

ST_Slope(rast)

Вычисляет угол наклона поверхности (полезно для рельефа)

Topology. 

Работа с топологическими сетями: узлы, ребра, границы

ST_TopologyNodes(topology)

Получает все узлы топологической сети

ST_TopologyEdges(topology)

Получает линии между узлами

ST_TopologyFaces(topology)

Возвращает области, образованные смежными границами

ST_TopologyRedefine(topology, geom)

Обновляет топологию при изменении объекта

ST_TopologyValidate(topology)

Проверяет корректность топологической модели

ST_TopologyAdjacentFaces(face)

Получает смежные полигоны для заданного полигона

ST_TopologyFaceArea(face)

Возвращает площадь топологического полигона

ST_TopologyEdgeNodes(edge)

Возвращает узлы, соединенные ребром топологии

Как развернуть БД 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. В панели управления в верхнем меню открываем Продукты → Облачные базы данных.

Скриншот панели управления Selectel.

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

Скриншот панели управления Selectel.

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

Скриншот панели управления Selectel.

Со всеми деталями вы можете ознакомиться в документации по созданию кластера PostgreSQL.

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

Скриншот панели управления Selectel.

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

6. Переходим во вкладку Базы данных и нажимаем Создать базу данных

Скриншот панели управления Selectel.

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

Скриншот панели управления Selectel.

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

Скриншот панели управления Selectel.

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

10. Проверяем установленные расширения командой \dx:

Скриншот панели управления Selectel.

Если все необходимые расширения есть, переходим к самому интересному — изучению функций 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-запросов. Не нужно использовать отдельные системы или приложения, конвертировать форматы или вручную рассчитывать расстояния и проверять пересечения. Расширение добавляет поддержку пространственных объектов — от простых точек до сложных полигонов, а также позволяет применять к ним сразу десятки готовых функций. 

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

Для опытных специалистов расширение позволяет избавиться от рутины и ускорить решение повседневных задач. Теперь можно сконцентрироваться на логике и ценности данных, а не на технических ограничениях.

Комментарии (2)


  1. Akina
    25.08.2025 09:13

    GIS - гораздо более применимая система, чем вы описываете. И я считаю, что такого рода статьи категорически НЕ способствуют широкому применению GIS на практике. Причина проста. GIS - это система для работы с двумерными данными. ЛЮБЫМИ двумерными данными. И геоинформация - всего лишь одно из приложений, но далеко не единственное. Работа с графиками, изображениями и пр. - прекрасные места для использования этого расширения. Но вот именно это применение почему-то практически всегда в статьях отсутствует. И зачастую задачи, которые элементарно решаются применением геометрических данных, на практике решаются ну очень заковыристыми методами, потому что программисту в голову не пришло. А не пришло потому, что он не читал и не видел ТАКОГО применения геобиблиотеки, потому что никто не взял себе за труд описать её применение во всех областях, где она по делу, а не только в самой очевидной.

    Жаль...


    1. Sleuthhound
      25.08.2025 09:13

      Это и не статья о PostGIS, а промо-ролик что у нас в облаке есть PostGIS. Все, что описано в статье есть в документации и перемалывать одно и то же нет смысла.

      Реально интересные вещи о PostGIS разве что на конференциях рассказывают.