Работа с данными, хранящимися в jsonb контейнере
Contents
Работа с данными, хранящимися в jsonb контейнере#
Атрибуты, хранящиеся в jsonb контейнере#
Предисловие#
В нашей системе есть два типа атрибутов:
Базовые, определяемые в odm-файле
Json-хранимые - определяемые как через интерфейс приложения(в том числе универсальные характеристики), так и через исходный код
В самом простом случае при создании json-атрибута в интерфейсе приложения он будет отмечен как объектная характеристика, хранящаяся в json.
Редактировать такие атрибуты можно на вкладке объектных характеристик соответствующего класса. Обработка этих атрибутов уже реализована средствами фреймворка.
Внимание
В базе для хранения данных используется контейнер типа jsonb
Получение и установка атрибутов, хранимых в json#
Получение и обработка данных методами api текущего класса для объектных характеристик#
Примечание
Все json-хранимые объектные характеристики и универсальные характеристики хранятся в контейнере с именем jObjAttrs_dz
. И все перечисленные далее методы чтения и записи данных для атрибутов-характеристик работают именно с этим контейнером.
Для атрибута, хранимого в json и настроенного как объектная характеристика в JObjectAttrApi.scala
, реализован набор методов для записи и чтения данных из контейнера:#
Запись по id#
ru.bitec.app.btk.class_.service.objectAttr.JObjectAttrApi#setObjAttrValue(rop: ApiRop, idpAttr: NLong, pValue: Any)
Метод установки значения json атрибута по его id
Вызвать этот метод можно от апи вашего класса
rop
- rop-а, чей атрибут вы хотите изменитьidpAttr
- id атрибутаpValue
- значение, которое хотите установить атрибуту
Метод проверяет, что переданное значение совпадает с типом данных, настроенным на атрибуте.
Запись по имени#
ru.bitec.app.btk.class_.service.objectAttr.JObjectAttrApi#setObjAttrValue(rop: ApiRop, spAttrName: NString, pValue: Any)
Метод установки значения json атрибута по его системному имени
Вызвать этот метод можно от апи вашего класса
rop
- rop-а, чей атрибут вы хотите изменитьspAttrName
- системное имя атрибутаpValue
- значение, которое хотите установить атрибуту
Метод проверяет наличие настроенного атрибута в классе Btk_Attribute, если атрибут не найден, то кидает ошибку.
После успешного прохождения проверки вызывается метод def setObjAttrValue(rop: ApiRop, idpAttr: NLong, pValue: Any).
Внимание
При передаче значения для устанавливаемого атрибута необходимо передавать данные, приведенные к соответствующему типу!
Чтение по id#
ru.bitec.app.btk.class_.service.objectAttr.JObjectAttrApi#getObjAttrValue(rop: ApiRop, idpAttr: NLong)
Метод получения значения json атрибута по его id
Так же, как и предыдущие, проверяет наличие атрибута в Btk_Attribute
Вызвать этот метод можно от апи вашего класса
rop
- rop-а, чей атрибут вы хотите получитьidpAttr
- id атрибута
Чтение по системному имени#
ru.bitec.app.btk.class_.service.objectAttr.JObjectAttrApi#getObjAttrValue(rop: ApiRop, spAttrName: NString)
Метод получения значения json атрибута по его системному имени
Так же, как и предыдущие, проверяет наличие атрибута в Btk_Attribute
Вызвать этот метод можно от апи вашего класса
rop
- rop-а, чей атрибут вы хотите получитьidpAttr
- id атрибута
Метод проверяет наличие настроенного атрибута в классе Btk_Attribute, если атрибут не найден, то кидает ошибку.
После успешного прохождения проверки вызывается метод def getObjAttrValue(rop: ApiRop, idpAttr: NLong).
Универсальные характеристики(UC)#
Универсальные характеристики являются отдельным сервисом, позволяющим подключить к объектам класса дополнительные атрибуты и не требующим компиляции исходного кода.
Универсальные характеристики хранятся в справочнике Btk_UniversalCharacteristic.
При подключении универсальной характеристики в качестве атрибута к целевому классу итоговые данные по этому атрибуту-характеристике записываются в контейнер jObjAttrs_dz
, туда же, где хранятся значения json объектных характеристик.
Получение и обработка данных методами api текущего класса для универсальных характеристик#
Запись UC по id#
ru.bitec.app.btk.class_.service.objectAttr.JObjectAttrApi#setUniCharValue(rop: ApiRop, idpUniChar: NLong, pValue: Any)
Метод установки значения UC json атрибута по его id
Вызвать этот метод можно от апи вашего класса
rop
- rop-а, чей атрибут вы хотите изменитьidpUniChar
- id UC атрибутаpValue
- значение, которое хотите установить атрибуту. Возможна множественная установка значений
Метод проверяет, что переданное значение совпадает с типом данных, настроенным на атрибуте.
Запись по имени#
ru.bitec.app.btk.class_.service.objectAttr.JObjectAttrApi#setUniCharValue(rop: ApiRop, spUniCharName: NString, pValue: Any)
Аналогичен предыдущему. Предварительно ищет id универсальной характеристики по системному имени. После вызывает метод вызывается метод def setUniCharValue(rop: ApiRop, idpUniChar: NLong, pValue: Any). Возможна множественная установка значений.
Чтение UC по id#
ru.bitec.app.btk.class_.service.objectAttr.JObjectAttrApi#getUniCharValue(rop: ApiRop, idpUniChar: NLong)
Метод получения значения json атрибута по его id
Так же как и предыдущие проверяет наличие атрибута в Btk_Attribute
Вызвать этот метод можно от апи вашего класса
rop
- rop-а, чей атрибут вы хотите получитьidpUniChar
- id UC атрибута
Чтение UC по системному имени#
ru.bitec.app.btk.class_.service.objectAttr.JObjectAttrApi#getUniCharValue(rop: ApiRop, spUniCharName: NString)
Проверяет наличие универсальной характеристики по системному имени. После вызывает метод def getUniCharValue(rop: ApiRop, idpUniChar: NLong).
Чтение и запись иных данных в json контейнер#
Если вам нужно хранить иные структуры данных, не подходящие под прошлые пункты, тогда:
Для получения доступа к данным в контейнере используйте метод подключения json документа
ru.bitec.app.gtk.eclipse.json.JEmbeddedDoc#parseProperty
с последующей конвертацией к JObject и методru.bitec.app.gtk.eclipse.json.JEObject#set
Для добавления или перезаписи значения по ключу:
JEmbeddedDoc.parseProperty(rop,"Имя json контейнера").asJObject.set(key: NString, value: NString)
Внимание
Если попытаться напрямую установть значение в атрибут, можно затереть данные из контейнера, которые там присутствовали ранее!
Примечания по работе с jsnonb контейнерами#
Все строковые значения необходимо заворачивать в двойные кавычки
"
text"
Если вы пытаетесь поставить в нестроковое поле пустое значение, то используйте значение „null“
Оператор
->
возвращает элемент типаjsonb
. Оператор->>
возвращает элемент типаtext
. Для промежуточных манипуляций с объектами контейнера используйте->
, а для получения конечного значения->>
При добавлении значений при помощи
||
илиjsonb_set()
к уже существующему набору(напримерjtypesizeattrs
) пар ключ-значение необходимо оборачивать его вcoalesce(jtypesizeattrs, '{}':: jsonb)
, так как еслиjtypesizeattrs
до этого был null, то прибавляя у нему любое значение, мы получим nullПри добавлении значений при помощи
||
илиjsonb_set()
к уже существующему массиву(напримерjSign_dz
) необходимо оборачивать его вcoalesce(jSign_dz, '[]':: jsonb)
так как еслиjSign_dz
до этого был null, то, прибавляя к нему любое значение, мы получим null
Работа с контейнером jObjAttrs_dz#
В контейнере jObjAttrs_dz
данные хранятся в виде мапы, соответственно сразу можно использовать метод ->>
для получения конечных данных из этой мапы.
Например:
Получение json-атрибута из контейнера:
select w.jObjAttrs_dz ->> 'idJsonAttr' as idJsonAttr, cast(w.jObjAttrs_dz ->> 'bJsonAttr' as numeric(1)) as bJsonAttr, cast(w.jObjAttrs_dz ->> 'nJsonAttr' as numeric(38, 18)) as nJsonAttr, w.jObjAttrs_dz ->> 'sJsonAttr' as sJsonAttr, cast(w.jObjAttrs_dz ->> 'dJsonAttr' as date) as dJsonAttr, cast(w.jObjAttrs_dz ->> 'dJsonAttr' as timestamp) as dJsonAttrDateTime from ( select '{"idJsonAttr": 123456, "bJsonAttr": 0, "nJsonAttr": 0.01, "sJsonAttr": "Some test string", "dJsonAttr": "01.01.2101 10:10:10"}' :: jsonb as jObjAttrs_dz) w return: |idJsonAttr|bJsonAttr| nJsonAttr| sJsonAttr| dJsonAttr| dJsonAttrDateTime| | 123456| 0|0.010000000000000000|"Some test string"|"2101-01-01"|"2101-01-01 10:10:10.000"|
Работа с обобщенными json контейнерами в Postgres#
Например:
Получение поля из массива
select (w.jsign_dz -> 1) -> 'sFIO' -- 1 - индекс массива. Отсчет ведётся с 0. sFIO - имя искомого поля from (select '[ {"sFIO": "Степанова Е.В.", "sPosition": "Нач. отдела", "idEmployee": null, "idDepartment": 102696, "sBasisDocument": null, "idBlankSignType": 95401}, {"sFIO": "Линчук Владимир Владимирович", "dDate": "04.12.2019", "sPosition": null, "idEmployee": 21035, "sBasisDocument": null, "idBlankSignType": 95402} ]' :: jsonb as jsign_dz) w return: "Линчук Владимир Владимирович"
Апдейтим поле в массиве записей. В этом случае используем метод jsonb_set. Аргументы - первоначальное значение, путь к изменяемому значению, устанавливаемое значение
update stk_warrantin w set jsign_dz = jsonb_set(coalesce(w.jSign_dz, '[]':: jsonb),'{1,sFIO}', '"Иванов Ива Иванович"') -- {1,sFIO} - путь к интересуемому полю 1 - индекс в массиве. sFIO - поле в массиве. where id = someId
select jsonb_set(coalesce(w.jSign_dz, '[]':: jsonb),'{1,sFIO}', '"Иванов Ива Иванович"') from (select '[ {"sFIO": "Степанова Е.В.", "sPosition": "Нач. отдела", "idEmployee": null, "idDepartment": 102696, "sBasisDocument": null, "idBlankSignType": 95401}, {"sFIO": "Линчук Владимир Владимирович", "dDate": "04.12.2019", "sPosition": null, "idEmployee": 21035, "sBasisDocument": null, "idBlankSignType": 95402} ]' :: jsonb as jsign_dz) w return: [ {"sFIO": "Степанова Е.В.", "sPosition": "Нач. отдела", "idEmployee": null, "idDepartment": 102696, "sBasisDocument": null, "idBlankSignType": 95401}, {"sFIO": "Иванов Ива Иванович", "dDate": "04.12.2019", "sPosition": null, "idEmployee": 21035, "sBasisDocument": null, "idBlankSignType": 95402} ]
Удаляем запись из результирующего массива (пару ключ - значение из объекта)
select w.jsign_dz - 1 from (select '[ {"sFIO": "Степанова Е.В.", "sPosition": "Нач. отдела", "idEmployee": null, "idDepartment": 102696, "sBasisDocument": null, "idBlankSignType": 95401}, {"sFIO": "Линчук Владимир Владимирович", "dDate": "04.12.2019", "sPosition": null, "idEmployee": 21035, "sBasisDocument": null, "idBlankSignType": 95402} ]' :: jsonb as jsign_dz) w return: [ {"sFIO": "Степанова Е.В.", "sPosition": "Нач. отдела", "idEmployee": null, "idDepartment": 102696, "sBasisDocument": null, "idBlankSignType": 95401} ]
Удаляем поле из мапы
select (w.jsign_dz -> 0) - 'sFIO' from (select '[ {"sFIO": "Степанова Е.В.", "sPosition": "Нач. отдела", "idEmployee": null, "idDepartment": 102696, "sBasisDocument": null, "idBlankSignType": 95401}, {"sFIO": "Линчук Владимир Владимирович", "dDate": "04.12.2019", "sPosition": null, "idEmployee": 21035, "sBasisDocument": null, "idBlankSignType": 95402} ]' :: jsonb as jsign_dz) w return: {"sPosition": "Нач. отдела", "idEmployee": null, "idDepartment": 102696, "sBasisDocument": null, "idBlankSignType": 95401}
Добавляем запись в массив. В этом случае работаем с объединением двух массивов. Необходимо задать строку с новым объектом массива и добавить её с помощью операции
||
к старому значениюselect coalesce(w.jSign_dz, '[]':: jsonb) || '[ {"sFIO": "Петров Е.В.", "sPosition": "тест", "idEmployee": null, "idDepartment": 102696, "sBasisDocument": null, "idBlankSignType": 95401} ]' :: jsonb from (select '[ {"sFIO": "Степанова Е.В.", "sPosition": "Нач. отдела", "idEmployee": null, "idDepartment": 102696, "sBasisDocument": null, "idBlankSignType": 95401}, {"sFIO": "Линчук Владимир Владимирович", "dDate": "04.12.2019", "sPosition": null, "idEmployee": 21035, "sBasisDocument": null, "idBlankSignType": 95402} ]' :: jsonb as jsign_dz) w return: [ {"sFIO": "Степанова Е.В.", "sPosition": "Нач. отдела", "idEmployee": null, "idDepartment": 102696, "sBasisDocument": null, "idBlankSignType": 95401}, {"sFIO": "Линчук Владимир Владимирович", "dDate": "04.12.2019", "sPosition": null, "idEmployee": 21035, "sBasisDocument": null, "idBlankSignType": 95402}, {"sFIO": "Петров Е.В.", "sPosition": "тест", "idEmployee": null, "idDepartment": 102696, "sBasisDocument": null, "idBlankSignType": 95401} ]
Можно полностью перезаписать контейнер jSign_dz. Можно сформировать строку при помощи обычных строковых методов и полностью перезаписать атрибут jSign_dz, используя приведения строки к типу jsonb и соблюдая синтаксис jsonb
update stk_warrantin w set jsign_dz = ('[{"sFIO": "' || 'Тест' || '", "sPosition": "тест", "idEmployee": null, "idDepartment": ' || '1' || ', "sBasisDocument": null, "idBlankSignType": 95401}]') :: jsonb where id = someId
Разворачиваем массив подписей в записи
select value ->> 'sFIO' as sFIO from jsonb_array_elements( '[ {"sFIO": "Степанова Е.В.", "sPosition": "Нач. отдела", "idEmployee": null, "idDepartment": 102696, "sBasisDocument": null, "idBlankSignType": 95401}, {"sFIO": "Линчук Владимир Владимирович", "dDate": "04.12.2019", "sPosition": null, "idEmployee": 21035, "sBasisDocument": null, "idBlankSignType": 95402} ]' :: jsonb) v return: 1: `Степанова Е.В.` 2: `Линчук Владимир Владимирович`
Индексный доступ в jsonb объектах#
Postgresql позволяет индексировать поля с типом jsonb
в двух вариантах:
Индексация существования ключа на верхнем уровне объекта. Поддерживает операторы
?
,?&
и?|
Пример индекса:CREATE INDEX idxSomeName ON SomeTable USING GIN (jData)
Индексация существования пары путь/значение. Поддерживает оператор
@>
CREATE INDEX idxSomeName ON SomeTable USING GIN (jData jsonb_path_ops)
Поле jObjectAttrs_dz
, в котором хранятся значения json-атрибутов
и универсальных характеристик
, по умолчанию использует второй тип индекса.
Исследование производительности запросов#
Характеристики теста#
База данных:
PostgreSQL 16.5 (Debian 16.5-1.pgdg110+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 10.2.1-6) 10.2.1 20210110, 64-bit
64 Gb Ram, CPU: 3.5Ghz х 8, SSD
Таблица содержит индексируемое поле с типом
jsonB
. Тип индексаgin (jsonb_path_ops)
Количество строк в таблице: 80 млн.
Каждая строка содержит jsonb-объект, в котором 200 ключей:
50 ключей, которые имеют 10 возможных значений (имена начинаются на attr_10_vals_)
50 ключей, которые имеют 2 возможных значения (0 или 1) (имена начинаются на attr_bool_vals_)
50 ключей, которые имеют 100 возможных значений (имена начинаются на attr_100_vals_)
50 ключей, которые имеют уникальные значения (имена начинаются на attr_1_vals_)
Данные формировались со сдвигом на каждой формируемой строке, для получения разреженных данных.
Всего возможных ключей: 1600
400 ключей, которые имеют 10 возможных значений (имена начинаются на attr_10_vals_)
400 ключей, которые имеют 2 возможных значения (0 или 1) (имена начинаются на attr_bool_vals_)
400 ключей, которые имеют 100 возможных значений (имена начинаются на attr_100_vals_)
400 ключей, которые имеют уникальные значения (имена начинаются на attr_1_vals_)
ddl-выражение
для создания таблицы:CREATE TABLE public.tst_testobjattrs ( scaption text NULL, jobj jsonb NULL ); CREATE INDEX idx_tst_testobjattrs_jidext_dz ON public.tst_testobjattrs USING gin (jobj jsonb_path_ops);
pg/sql-выражение
для генерации тестовых данных:DO $$ begin FOR t IN 1 .. 800 loop EXECUTE (' with attrs as materialized ( select ''attr_10_vals_'' || cast(t as text) as sName ,(select array_agg(cast(v % 10 + t as text) || ''/'' || cast(v % 10 + t as text)) from generate_series(t*10, t*10 + 99) v ) as vals ,t as nNum from generate_series(1, 400) t union all select ''attr_bool_vals_'' || cast(t as text) as sName ,(select array_agg(cast((v + t) % 2 as text)) from generate_series(t*10, t*10 + 99) v ) as vals ,t as nNum from generate_series(401, 800) t union all select ''attr_100_vals_'' || cast(t as text) as sName ,(select array_agg(cast(v as text) || ''/'' || cast(v as text)) from generate_series(t*10, t*10 + 99) v ) as vals ,t as nNum from generate_series(801, 1200) t union all select ''attr_1_vals_'' || cast(t as text) as sName ,(select array_agg(case when v > 0 then cast(t as text) || ''/'' || cast(t as text) end) from generate_series(1, 100) v ) as vals ,t as nNum from generate_series(1201, 1600) t ) insert into tst_testobjattrs select ''capt'' || t::text, ( select jsonb_object(array_agg(a.sName), array_agg(a.vals[t % 100])) from generate_series(t % 400, t % 400 + 39) v cross join generate_series(1, 1201, 400) attrStep join attrs a on a.nNum = v + attrStep ) as jObj from generate_series(1, 100000) t; '); commit; end loop; END $$;
Размер таблицы:
данные 208 Гб
индекс 56 Гб
Запрос на точное совпадения значения#
В этом запросе точно известны все значения атрибутов, по которым требуется найти строки
Выполняемый запрос:
select *
from tst_testobjattrs t
where t.jobj @> '{"attr_10_vals_102": "103/103"}'
and t.jobj @> '{"attr_10_vals_94": "95/95"}'
and t.jobj @> '{"attr_10_vals_73": "74/74"}'
and t.jobj @> '{"attr_10_vals_63": "64/64"}'
and t.jobj @> '{"attr_1_vals_1300": "1300/1300"}'
and t.jobj @> '{"attr_100_vals_888": "8941/8941"}'
and t.jobj @> '{"attr_bool_vals_467": "1"}'
and t.jobj @> '{"attr_bool_vals_494": "1"}'
План выполнения запроса. Используется индекс:
Запросы на неточное совпадение значения#
Запросы like#
Существующий индекс#
В этой главе описывается возможности индексного доступа, при использовании оператора like
.
Индекс gin (jsonb_path_ops)
не обеспечивает возможность индексного доступа при использовании оператора like
.
Выполняемый запрос:
select *
from tst_testobjattrs t
where (t.jobj ->> 'attr_10_vals_4') not like '1%'
План выполнения. Полный просмотр таблицы:
Если выполнить запрос с условием, в котором будет точное совпадение значения и условие по like
, то будет использоваться индекс с дополнительной фильтрацией.
Выполняемый запрос:
select *
from tst_testobjattrs t
where t.jobj @> '{"attr_10_vals_10": "10/10"}'
and t.jobj ->> 'attr_10_vals_4' like '1%'
План выполнения. Используется индекс:
Дополнительный функциональный индекс#
Для решения задачи поиска значения, используя оператор like
, возможно создать функциональный индекс.
Поиск по началу строки.
Создаем индекс с классом операторов
text_pattern_ops
create index tst_testobjattrs_idx_text on tst_testobjattrs ((jobj ->> 'attr_10_vals_3') text_pattern_ops)
Время создания: 5 мин 20 сек. размер: 528 МБ
Выполняем запрос
select * from tst_testobjattrs t where (t.jobj ->> 'attr_10_vals_3') like '100%'
План запроса, используется индекс:
Поиск по началу строки.
Создаем индекс с классом операторов
gin_trgm_ops
. Потребуется подключенный модульpg_trgm
(поставляется по умолчанию с нашей системой). Модуль который разбивает слова на триграммы и выполняет поиск по ним. Отсюда следует, что искать строки следует от 3-х символов и большеccreate index tst_testobjattrs_idx_text_trg on tst_testobjattrs using gin ((jobj ->> 'attr_10_vals_2') gin_trgm_ops)
Время создания: 7 мин 8 сек. размер: 98 МБ
Выполняем запрос
select * from tst_testobjattrs t where (t.jobj ->> 'attr_10_vals_2') like '%10/%'
План запроса, используется индекс:
Запрос диапазона по числам#
Для решения задачи поиска по диапазону чисел (<
, <=
, >
, >=
) возможно создать функциональный индекс.
Создаем индекс
create index tst_testobjattrs_idx_number on tst_testobjattrs (((jobj -> 'nNumber') :: numeric))
Время создания: 4 мин 58 сек. размер: 1.7 ГБ
Выполняем запрос
select * from tst_testobjattrs t where (jobj -> 'nNumber') :: numeric >= 10 and (jobj -> 'nNumber') :: numeric <= 20
План запроса, используется индекс:
Запрос диапазона по датам#
В json
нет такого типа данных как даты, потому система хранит даты в виде строк в формате DD.MM.YYYY HH24:MI:SS
. По этому для поиска по дате необходимо создать функциональный индекс, который бы переводил строку в дату.
Давайте попробуем создать индекс:
create index tst_testobjattrs_idx_json_date2 on tst_testobjattrs (to_date(jobj ->> 'dDate', 'DD.MM.YYYY HH24:MI:SS'))
Получим ошибку:
SQL Error [42P17]: ОШИБКА: функции в индексном выражении должны быть помечены как IMMUTABLE
Для создания функциональный индексов требуется использовать только функции, помеченные как IMMUTABLE
.
Т.е. при одних и тех же входящих параметрах результат функции не должен изменяться.
Функция to_date
зависит от локали базы и не может использоваться при индексации.
По этому алгоритм действий следующий:
Создаем функцию конвертации строки в дату. Т.к. формат у нас жестко фиксирован, то результат функции всегда будет одинаковым, и мы можем пометить ее как
IMMUTABLE
:create function strToDate_tst(stringDate text) RETURNS timestamp LANGUAGE sql AS $function$ select to_date(stringDate, 'DD.MM.YYYY HH24:MI:SS') $function$ IMMUTABLE;
Создаем индекс
create index tst_testobjattrs_idx_json_date on tst_testobjattrs (strToDate_tst(jobj ->> 'dDate'))
Время создания: 10 мин 7 сек. размер: 528 МБ
Выполняем запрос
select * from tst_testobjattrs t where strToDate_tst((t.jobj ->> 'dDate')) between current_date - interval '100 DAY' and current_date
План запроса, используется индекс:
Выводы#
При запросе строк по точному совпадению значения необходимо использовать оператор
@>
Пример запроса:
select * from tst_testobjattrs t where t.jobj @> '{"attr_10_vals_102": "103/103", "attr_10_vals_94": "95/95"}'
Для поиска по началу строки (like с процентом справа) требуется создать дополнительный функциональный индекс с классом операторов
text_pattern_ops
.Пример индекса:
create index tst_testobjattrs_idx_text on tst_testobjattrs ((jobj ->> 'attr_10_vals_3') text_pattern_ops)
Для поиска по вхождению строки (like с процентом справа и слева) требуется наличие модуля
pg_trgm
(поставляется по умолчанию с нашей системой) создать дополнительный функциональныйgin
-индекс с классом операторовgin_trgm_ops
.Пример индекса:
create index tst_testobjattrs_idx_text_trg on tst_testobjattrs using gin ((jobj ->> 'attr_10_vals_2') gin_trgm_ops)
Для поиска по интервалу числовых значений требуется создать доп. функциональный индекс.
Пример индекса:
create index tst_testobjattrs_idx_number on tst_testobjattrs (((jobj -> 'nNumber') :: numeric))
Для поиска по интервалу дат требуется создать доп. функциональный индекс и использовать
immutable
-функцию конвертации строки в дату.Пример функции:
create function strToDate_tst(stringDate text) RETURNS timestamp LANGUAGE sql AS $function$ select to_date(stringDate, 'DD.MM.YYYY HH24:MI:SS') $function$ IMMUTABLE;
Пример индекса:
create index tst_testobjattrs_idx_json_date on tst_testobjattrs (strToDate_tst(jobj ->> 'dDate'))
Недостатки функциональных индексов в том, что на каждый ключ нужен отдельный индекс, что вызывает увеличение времени вставки и изменения записей таблицы, и увеличивает размер, занимаемый на диске.