В прошлой статье "Пример использования диапазонного типа данных" я на реальном примере рассмотрел, чем может быть полезен специальный тип для хранения диапазонов которые существует в PostgreSQL. В комментариях поступило предложение пойти дальше и воспользоваться типом box. Т.е. сохранить диапазон в виде объекта геометрии. Немного непривычно. Но сказано - сделано! Плюсы и минусы хранения КВС ОСАГО в виде box рассмотрю в заметке. Публикация является дополнением к указанной статье. Так же я подготовил все 4 вариант схем внутри демки с docker, поэтому примеры можно позапускать у себя. Кому ближе видео версия, то в конце заметки есть ссылка на полное видео данных публикаций на Youtube.

Предметная область

Кратко напомню, что КВС – коэффициент страховых тарифов в зависимости от возраста и стажа водителя (КВС). Зависимость представлена в таблице:

Здесь мы видим диапазоны чисел по входным критериям (стаж и возраст) и попробуем их сохранить в box типе. Итак четвертый вариант хранения диапазонов.

Схема D: Структура базы с геометрией

Как я уже упоминал данная схема появилась уже после выхода первой статьи. @ptr128в комментарии предложил пойти еще дальше и свести схему к таблице всего лишь с 2 колонками. С переходом на геометрию и использование тип данных box. Но для полного понимания как это работает нужно пояснение, каким образом данные в таблице превращаются в прямоугольники на плоскости. Для этого я нарисовал такой вот схему:

Для создания box нужно взять всего лишь две противоположные вершины. В таблице для величины КВС 1,87 есть диапазон возраста 16-21 и диапазон стажа 0-2. Мы можем задать две точки с координатами (16, 0) и (21, 2). Значение КВС внутри этой зоны 1,87. Следуя этой логике я перевел все значения в набор прямоугольников. Вот эти прямоугольники мы с базу и сохраняем.

Схема базы при использовании типа box получается такой:

CREATE TABLE pg_range_d__kvs
(
    "age_experience" box           not null,
    "value"          numeric(4, 2) not null,

    exclude using gist (age_experience WITH &&)
);
comment on column pg_range_d__kvs.age_experience is 'Возраст-Стаж';
comment on column pg_range_d__kvs.value is 'Значение КВС';

Ограничение-исключения EXCLUDE USING GIST убережет нас от ошибочной вставки пересекающихся диапазонов. Производим вставку данных:

Синтаксис вставки прямоугольников (порядок вершин не имеет значения):

INSERT INTO pg_range_d__kvs VALUES ('((16,0),(21,2))', 1.87);

Как видим, в этом случае получается 20 записей (их можно сократить до 15). Запрос на получение коэффициента имеет вид:

SELECT value FROM pg_range_d__kvs WHERE age_experience @> POINT(22,3);

Сравнение вариантов

Привожу таблицу сравнения всех 4 вариантов схемы базы данных.Как вы уже могли убедиться, при использовании диапазонного типа данных у нас получается минимальное количество строк, простой запрос и контроль «непересечения» диапазонов. Для большей наглядности я сделал сводную таблицу:

Запрос

Контроль «непересечения»

Визуальное удобство работы

Одна таблица

простой

да

среднее,
много данных

Три таблицы

сложный

нет

сложное

Таблица с диапазонами

простой

да

простое

Таблица с прямоугольниками

простой

да

среднее,
требуется график

Вариант с box на практике для решения данной задачи я использовать не рекомендую и привожу его чисто из спортивного интереса.

Демка с базами запакованными в docker

Видео версия публикаций и вопросов

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


  1. ptr128
    21.12.2022 12:44
    +3

    А не было мысли сравнить реализации еще и по производительности, измерив время выборки значений КВС, например, для миллиона сгенерированных случайных данных?


    1. alekciy Автор
      22.12.2022 09:47

      Для КВС практического смысла нет. Я не зря нашел ограничение сверху и ввел его в ТЗ. Количество данных получилось ограниченное и небольшой, поэтому даже без индексов это работало бы быстро.

      Но при желании можно наполнить базу и милионами записей. Для этого я и завел эти схемы в docker. Любой читатель может себе склонировать, запустить и поиграться с идексами и количеством данных. Все sql для этого есть в репозитории.


      1. ptr128
        22.12.2022 10:33

        Может я не точно выразился, но я имел ввиду миллион записей водителей со случайным возрастом и стажем, что вполне нормально для страховой компании, а не миллион записей КВС.