Руководство пользователя mxnumeric

Обзор

Тип numeric в PostgreSQL (далее — pg_numeric) обеспечивает более высокую точность по сравнению с аналогичными типами в других СУБД, однако его реализация сложнее и даёт относительно низкую производительность. Из-за архитектурных ограничений pg_numeric не поддерживает эффективную векторизацию. В результате в векторизованных движках выполнения он не приносит преимуществ по скорости — и зачастую работает медленнее, чем невекторизованное выполнение из-за накладных расходов совместимости. По сравнению с векторизованными целочисленными или вещественными типами pg_numeric обычно на 1–2 порядка медленнее.

Для повышения производительности при работе с числовыми данными YMatrix вводит тип mxnumeric с ограниченной точностью — до 38 цифр. Этот тип предоставляется через расширение mxnumeric.

Установка и обновление

mxnumeric как тип numeric по умолчанию

Начиная с версии 6.5 mxnumeric устанавливается и включается по умолчанию как тип numeric. Дополнительная установка или конфигурация не требуются: после инициализации базы данных все ссылки на numeric разрешаются в mxnumeric.

Тип mxnumeric реализован как public.numeric. Исходный тип pg_catalog.numeric остаётся доступным и не изменяется.

Ручная установка

Установите расширение стандартной командой PostgreSQL:

CREATE EXTENSION mxnumeric;

После успешной установки в текущей базе создаётся тип public.numeric. Встроенный тип pg_catalog.numeric остаётся без изменений.

Обновление расширения

При выпуске исправлений ошибок или оптимизаций обновление mxnumeric обычно сводится к установке нового пакета — ручного вмешательства не требуется.

Однако если расширение добавляет или изменяет функции, операторы или другие объекты каталога, администраторам необходимо вручную обновить расширение в существующих кластерах. Процедура зависит от масштаба изменений. Ниже приведены инструкции для обновления с версии 0.1 до 0.2.

Обновление в существующей базе данных

Чтобы обновить mxnumeric в уже созданной базе данных:

-- Подключитесь к целевой базе данных
\c db1

-- Проверьте текущий статус и версию расширения
\dx mxnumeric

-- Способ 1: Обновление до конкретной версии
ALTER EXTENSION mxnumeric UPDATE TO '0.2';

-- Способ 2: Обновление до последней доступной версии
ALTER EXTENSION mxnumeric UPDATE;

Повторная установка расширения (DROP EXTENSION mxnumeric; CREATE EXTENSION mxnumeric;) также обновляет версию, но удаляет все столбцы типа public.numeric из-за зависимостей. Избегайте этого способа, если это не строго необходимо.

Обновление в шаблонных базах данных

Чтобы новые базы данных автоматически использовали актуальную версию mxnumeric, обновите расширение в шаблонных базах:

-- Обновите mxnumeric в template1
\c template1
ALTER EXTENSION mxnumeric UPDATE;

-- Обновите mxnumeric в template0 (сначала разрешите подключения)
\c postgres
ALTER DATABASE template0 ALLOW_CONNECTIONS ON;

\c template0
ALTER EXTENSION mxnumeric UPDATE;

\c postgres
ALTER DATABASE template0 ALLOW_CONNECTIONS OFF;

После этих действий любая новая база данных будет использовать последнюю версию mxnumeric по умолчанию.

Определение используемого типа mxnumeric

Поскольку pg_catalog.numeric и public.numeric сосуществуют, важно уметь отличать, какой из них используется.

Поддерживаются два распространённых метода:

  • Проверка GUC-параметра mx_force_system_types:
    Если mx_force_system_types = false, используется public.numeric.

    SHOW mx_force_system_types;
     mx_force_system_types
    -----------------------
     off
    (1 строка)
  • Проверка oid типа numeric:
    Если oid не равен 1700, используется public.numeric.

    SELECT 'numeric'::regtype::oid;
      oid
    -------
     13862
    (1 строка)

Чтобы определить, используют ли столбцы таблицы тип mxnumeric, воспользуйтесь вспомогательными функциями:

SELECT attnum, attname, type FROM mxnumeric.list_numeric_columns('t1');
 attnum | attname |        type
--------+---------+--------------------
      2 | col1    | pg_catalog.numeric
      3 | col2    | public.numeric
(2 строки)

SELECT attnum, attname, type FROM mxnumeric.list_numeric_columns('public', 't1');
 attnum | attname |        type
--------+---------+--------------------
      2 | col1    | pg_catalog.numeric
      3 | col2    | public.numeric
(2 строки)

Использование

Настройка GUC-параметра mx_force_system_types

Значение mx_force_system_types = false заставляет numeric разрешаться в public.numeric. При использовании mxnumeric как типа numeric по умолчанию (v6.5+), этот параметр по умолчанию имеет значение false.

  • true: используется pg_catalog.numeric.
  • false: используется public.numeric (то есть mxnumeric).

Диапазон точности

mxnumeric поддерживает точность от 1 до 38. Попытка объявить большую точность вызывает ошибку:

CREATE TABLE t2(a INT, b NUMERIC(39, 0));
ERROR:  NUMERIC precision 39 must be between 1 and 38

Арифметические результаты, превышающие 38-значную точность, вызывают ошибку переполнения:

-- Ожидаемый результат: NUMERIC(40,0) → превышает лимит mxnumeric
SELECT 12345678901234567890::public.numeric * 12345678901234567890::public.numeric;
ERROR:  value overflows numeric format (Error.cc:26)

-- pg_catalog.numeric обрабатывает без ошибки
SELECT 12345678901234567890::pg_catalog.numeric * 12345678901234567890::pg_catalog.numeric;
                ?column?
-----------------------------------------
 152415787532388367501905199875019052100

SELECT pg_typeof(12345678901234567890::pg_catalog.numeric * 12345678901234567890::pg_catalog.numeric);
 pg_typeof
-----------
 numeric

Переполнение масштаба

Если масштаб установлен в 8, а точность — в 38, операции, дающие более 8 знаков после запятой, вызывают переполнение:

-- pg_catalog.numeric поддерживает до 9 знаков после запятой
SELECT 123456789012345678901234567890.12345678::pg_catalog.numeric(38,8) * 0.9;
                 ?column?
------------------------------------------
 111111110111111111011111111101.111111102
(1 строка)

-- public.numeric вызывает переполнение
SELECT 123456789012345678901234567890.12345678::public.numeric(38,8) * 0.9;
ERROR:  value overflows numeric format (Error.cc:26)

Тип результата деления

Деление в mxnumeric возвращает тип DOUBLE PRECISION. В отличие от него, деление в pg_catalog.numeric возвращает NUMERIC.

Поскольку SQL не определяет требования к точности результата деления, а PostgreSQL требует, чтобы точность результата была не ниже, чем у float8, mxnumeric использует float8 для результатов деления, чтобы максимизировать производительность.

Это приводит к незначительной потере точности по сравнению с pg_catalog.numeric:

SELECT 1234.5678901234567890::pg_catalog.numeric(20,16) / 666;
      ?column?
--------------------
 1.8537055407259111
(1 строка)

-- В mxnumeric наблюдается небольшая потеря точности
SELECT 1234.5678901234567890::public.numeric(20,16) / 666;
      ?column?
--------------------
 1.8537055407259109

Типы возвращаемых значений функций

Следующие функции возвращают FLOAT8 вместо NUMERIC для повышения производительности:

  • exp()
  • ln()
  • log()
  • pow() / power()
  • sqrt()

Настройка возможностей

Некоторые возможности нельзя включить при создании расширения и требуют явной конфигурации.

Функция mxnumeric.set_config(text, bool) включает или отключает дополнительные возможности mxnumeric. Текущие настройки отображаются в представлении mxnumeric.configs:

SELECT * FROM mxnumeric.configs;
       config       | enabled |                                          description
--------------------+---------+------------------------------------------------------------------------------------------------
 linear_interpolate | f       | replace original linear_interpolate functions with mxnumeric version to support mxnumeric type
 mars3              | f       | create operator classes to support mars3 btree & brin index for mxnumeric type

Поддержка функции linear_interpolate

Встроенная функция ядра linear_interpolate() жёстко закодирована для работы только со встроенными типами и изначально не поддерживает mxnumeric. Поскольку эта функция используется редко, mxnumeric не включает такую поддержку по умолчанию.

Чтобы включить поддержку mxnumeric для linear_interpolate(), выполните:

SELECT mxnumeric.set_config('linear_interpolate', true);

Эта операция:

  • Переименовывает pg_catalog.linear_interpolate() для сохранения оригинальной версии,
  • Создаёт public.linear_interpolate(), оптимизированную для mxnumeric.

Чтобы вернуться к поведению по умолчанию:

SELECT mxnumeric.set_config('linear_interpolate', false);

Это восстанавливает pg_catalog.linear_interpolate() и удаляет версию из схемы public.

Поддержка индексов mars3

mars3 и mxnumeric — независимые расширения. Поскольку порядок установки mars3 не гарантирован, mxnumeric по умолчанию не предоставляет классы операторов mars3_btree и mars3_brin для типа mxnumeric.

Чтобы включить поддержку mxnumeric для индексов mars3, выполните:

SELECT mxnumeric.set_config('mars3', true);

Предварительное условие: Расширение matrixts должно быть уже установлено; в противном случае команда завершится ошибкой.

Чтобы отключить поддержку и удалить классы операторов:

SELECT mxnumeric.set_config('mars3', false);

Приложение

Справочник функций mxnumeric

Обычные функции

Обычные функции работают независимо от контекста (в отличие от агрегатных, которые применяются только внутри GROUP BY).

Математические функции
oid Имя UDF Схема назначения Потеря точности Исходный тип результата Оптимизированный тип результата Типы параметров Точность результата Тип функции Категория Псевдоним
1705 abs public N numeric numeric = plain math
1711 ceil public N numeric numeric (P,0) plain math
2167 ceiling public N numeric numeric (P,0) plain math ceil
1973 div public Y numeric double numeric, numeric plain math
1732 exp public Y numeric double numeric plain math
1376 factorial public N numeric bigint (MAX,0) plain math
1712 floor public N numeric numeric (P,0) plain math
1734 ln public Y numeric double numeric plain math
1736 log public Y numeric double numeric, numeric plain math
1741 log public Y numeric double numeric plain math
1481 log10 ? Y numeric double numeric plain math
1728 mod public N numeric numeric, numeric = plain math
1704 numeric_abs mxnumeric N numeric numeric = plain math abs
1724 numeric_add mxnumeric N numeric numeric, numeric + plain math
6997 numeric_dec mxnumeric N numeric numeric = plain math
1727 numeric_div mxnumeric Y numeric double numeric, numeric plain math
1980 numeric_div_trunc mxnumeric Y numeric double numeric, numeric plain math
1733 numeric_exp mxnumeric Y numeric double numeric plain math exp
111 numeric_fac mxnumeric N numeric bigint (MAX,0) plain math factorial
1764 numeric_inc mxnumeric N numeric numeric = plain math
1767 numeric_larger mxnumeric N numeric numeric, numeric = plain math
1735 numeric_ln mxnumeric Y numeric double numeric plain math ln
1737 numeric_log mxnumeric Y numeric double numeric plain math log
1729 numeric_mod mxnumeric N numeric numeric, numeric = plain math mod
1726 numeric_mul mxnumeric N numeric numeric, numeric * plain math
1739 numeric_power mxnumeric Y numeric double numeric, numeric plain math power
1766 numeric_smaller mxnumeric N numeric numeric, numeric = plain math
1731 numeric_sqrt mxnumeric Y numeric double numeric plain math sqrt
1725 numeric_sub mxnumeric N numeric numeric, numeric + plain math
1771 numeric_uminus mxnumeric N numeric numeric = plain math
1915 numeric_uplus mxnumeric N numeric numeric = plain math
1738 pow public Y numeric double numeric plain math power
2169 power public Y numeric double numeric plain math
1707 round public N numeric numeric, integer (P,arg) plain math
1708 round public N numeric numeric (P,0) plain math
1730 sqrt public Y numeric double numeric plain math
1709 trunc public N numeric numeric, integer (P,arg) plain math
1710 trunc public N numeric numeric (P,0) plain math
  • numeric_larger() и numeric_smaller() поддерживают агрегаты MIN()/MAX() и предполагают идентичную точность входных значений.
  • numeric_uminus() и numeric_uplus() реализуют унарные операции +x и -x.
  • Некоторые функции (например, log10(x)) являются обёртками на языке SQL (например, log(10,x)). Поскольку mxnumeric допускает только реализации на языке C, для них предоставлены отдельные C-реализации.
Функции операторов
oid Имя UDF Схема назначения Потеря точности Исходный тип результата Оптимизированный тип результата Типы параметров Точность результата Тип функции Категория
1769 numeric_cmp mxnumeric integer numeric, numeric plain oper
1718 numeric_eq mxnumeric bool numeric, numeric plain oper
1721 numeric_ge mxnumeric bool numeric, numeric plain oper
1720 numeric_gt mxnumeric bool numeric, numeric plain oper
1723 numeric_le mxnumeric bool numeric, numeric plain oper
1722 numeric_lt mxnumeric bool numeric, numeric plain oper
1719 numeric_ne mxnumeric bool numeric, numeric plain oper
Функции индексов
oid Имя UDF Схема назначения Потеря точности Исходный тип результата Оптимизированный тип результата Типы параметров Точность результата Тип функции Категория
6145 cdblegacyhash_numeric public integer numeric plain index
432 hash_numeric public integer numeric plain index
780 hash_numeric_extended public bigint numeric plain index
4141 in_range public bool numeric, numeric, numeric, boolean, boolean plain index
Функции приведения типов
oid Имя UDF Схема назначения Потеря точности Исходный тип результата Оптимизированный тип результата Типы параметров Точность результата Тип функции Категория
1745 float4 public real numeric plain cast
1746 float8 public double numeric plain cast
1783 int2 public smallint numeric plain cast
1744 int4 public integer numeric plain cast
1779 int8 public bigint numeric plain cast
3824 money public money numeric plain cast
1703 numeric public numeric numeric, int plain cast
1740 numeric public numeric integer plain cast
1742 numeric public numeric real plain cast
1743 numeric public numeric double plain cast
1781 numeric public numeric bigint plain cast
1782 numeric public numeric smallint plain cast
3449 numeric public numeric jsonb plain cast
3823 numeric public numeric money plain cast
7597 numeric2complex public complex numeric plain cast
3844 numrange public numrange numeric, numeric plain cast
3845 numrange public numrange numeric, numeric, text plain cast
3924 numrange_subdiff public double numeric, numeric plain cast
1772 to_char public text numeric, text plain cast
1777 to_number public numeric text, text plain cast
Вспомогательные функции
oid Имя UDF Схема назначения Потеря точности Исходный тип результата Оптимизированный тип результата Типы параметров Точность результата Тип функции Категория
3259 generate_series public N numeric numeric, numeric, numeric = plain util
3260 generate_series public N numeric numeric, numeric = plain util
3281 scale public integer numeric plain util
1706 sign public N numeric numeric = plain util
2170 width_bucket public integer numeric, numeric, numeric, integer plain util
Внутренние функции
oid Имя UDF Схема назначения Потеря точности Исходный тип результата Оптимизированный тип результата Типы параметров Точность результата Тип функции Категория
7082 interval_bound public N numeric numeric, numeric = plain internal
7083 interval_bound public N numeric numeric, numeric, integer = plain internal
7084 interval_bound public N numeric numeric, numeric, integer, numeric = plain internal
6082 linear_interpolate public numeric anyelement, anyelement, numeric, anyelement, numeric plain internal
1701 numeric_in mxnumeric numeric cstring, oid, integer (P,S) plain internal
1702 numeric_out mxnumeric cstring numeric plain internal
2460 numeric_recv mxnumeric numeric internal, oid, integer (P,S) plain internal
2461 numeric_send mxnumeric bytea numeric plain internal
3237 pg_lsn_mi ? N numeric pg_lsn, pg_lsn plain internal
3166 pg_size_pretty ? text numeric plain internal
2022 pg_stat_get_activity ? record integer plain internal
1136 pg_stat_get_wal ? record plain internal
3165 pg_wal_lsn_diff ? numeric pg_lsn, pg_lsn plain internal

Агрегатные функции

Обёртки
oid Имя UDF Схема Потеря точности Исходный тип результата Оптимизированный тип результата Типы параметров Точность результата Тип функции Категория
2100 avg public numeric bigint (MAX, S) agg
2101 avg public numeric integer (MAX, S) agg
2102 avg public numeric smallint (MAX, S) agg
2103 avg public numeric numeric (MAX, S) agg
2130 max public numeric numeric = agg
2146 min public numeric numeric = agg
2154 stddev public numeric bigint agg
2155 stddev public numeric integer agg
2156 stddev public numeric smallint agg
2159 stddev public numeric numeric agg
2724 stddev_pop public numeric bigint agg
2725 stddev_pop public numeric integer agg
2726 stddev_pop public numeric smallint agg
2729 stddev_pop public numeric numeric agg
2712 stddev_samp public numeric bigint agg
2713 stddev_samp public numeric integer agg
2714 stddev_samp public numeric smallint agg
2717 stddev_samp public numeric numeric agg
2107 sum public numeric bigint (MAX, S) agg
2114 sum public numeric numeric (MAX, S) agg
2718 var_pop public numeric bigint agg
2719 var_pop public numeric integer agg
2720 var_pop public numeric smallint agg
2723 var_pop public numeric numeric agg
2641 var_samp public numeric bigint agg
2642 var_samp public numeric integer agg
2643 var_samp public numeric smallint agg
2646 var_samp public numeric numeric agg
2148 variance public numeric bigint agg
2149 variance public numeric integer agg
2150 variance public numeric smallint agg
2153 variance public numeric numeric agg
Реализации
oid Имя UDF Схема Потеря точности Исходный тип результата Оптимизированный тип результата Типы параметров Точность результата Тип функции Категория
1964 int8_avg public numeric bigint[] agg helper legacy
1842 int8_sum public numeric numeric, bigint agg helper legacy
1833 numeric_accum mxnumeric internal internal, numeric agg helper
3548 numeric_accum_inv mxnumeric internal internal, numeric agg helper
1837 numeric_avg mxnumeric numeric internal agg helper
2858 numeric_avg_accum mxnumeric internal internal agg helper
3389 numeric_poly_avg mxnumeric numeric internal agg helper
3392 numeric_poly_stddev_pop mxnumeric numeric internal agg helper
3393 numeric_poly_stddev_samp mxnumeric numeric internal agg helper
3388 numeric_poly_sum mxnumeric numeric internal agg helper
3390 numeric_poly_var_pop mxnumeric numeric internal agg helper
3391 numeric_poly_var_samp mxnumeric numeric internal agg helper
2596 numeric_stddev_pop mxnumeric numeric internal agg helper
1839 numeric_stddev_samp mxnumeric numeric internal agg helper
3178 numeric_sum mxnumeric numeric internal agg helper
2514 numeric_var_pop mxnumeric numeric internal agg helper
1838 numeric_var_samp mxnumeric numeric internal agg helper