эффективно группировать множество полей, включая большой текст и jsonb

Заранее извиняюсь... многословный вопрос.

Предположим, у меня есть таблица table_x с 20 полями:

table_x_id (identity pk)
int1
int...
int8
text1
text...
text8
jsonb1
jsonb2

Теперь предположим, что я хочу поддерживать быстрый доступ к сгруппированным данным (скажем, полям int1, int2, text1_id, text2_id и jsonb1) в table_x. Назовите это Report 1. Данные на самом деле не играют важной роли в постановке этого вопроса, но вот воображаемый фрагмент из Report 1:

+-----------------------------------------------------------------------+
| int1value int2value text1value text2value jsonb1->item1 jsonb1->item2 |
+-----------------------------------------------------------------------+
|                                                       (table_x_id) 12 |
|                                                       (table_x_id) 20 |
|                                                       (table_x_id) 34 |
+-----------------------------------------------------------------------+

Теперь представьте, что у меня есть три или более подобных отчетов, и каждый отчет включает в себя группировку многих (но не всех) полей в table_x.

Каждое текстовое поле может легко достигать, скажем, 1000 символов, а поля jsonb, хотя и невелики, только усугубляют проблему.

Задача: ускорить группировку для отчетов.

Чтобы ускорить операции группирования и уменьшить размер строки table_x, я разбил уникальные значения текстовых полей (которые действительно сильно перекрываются) в отдельный text_table.

Теперь table_x это:

table_x_id (identity pk)
int1
int...
int8
text1_id (fk lookup)
text..._id (fk lookup)
text8_id (fk lookup)
jsonb1
jsonb2

Что касается группировки, то я думал сохранить хэш соответствующих столбцов внутри самого table_x, используя вызовы дайджеста() в триггере вставки/обновления. (Идея заключалась в том, чтобы преобразовать все соответствующие поля в моей группе в строки, соединить их вместе и выполнить хеширование полученной строки.)

Теперь table_x это:

table_x_id (identity pk)
int1
int...
int8
text1_id (lookup)
text..._id (lookup)
text8_id (lookup)
jsonb1
jsonb2
hash1_bytea (based on int1, int2, text1_id, text2_id and jsonb1)
hash2_bytea (based on int3, int7, text3_id, jsonb1 and jsonb2)
hash3_bytea (based on int2, int5, text1_id and jsonb2)

Теперь для отчета требуется больше поисков, но это быстро, и теперь мне нужно сгруппировать только по hash1_bytea, чтобы получить тот же результат Report 1.

Опасение: эквивалентные поля jsonb в разных строках могут не быть эквивалентными при сравнении их представлений jsonb::text. Из того, что я прочитал здесь, эти опасения кажутся оправданными.

Но если я не могу преобразовать значения jsonb в текст детерминированным образом, мое решение «хеш-поле внутри таблицы» развалится по швам.

Затем я решил сохранить значения jsonb в отдельном jsonb_table, где я гарантирую, что любая строка имеет уникальный объект jsonb.

jsonb_table is:

jsonb_id (identity pk)
jsonb (unique jsonb)

Для любого уникального объекта jsonb (не обращая внимания на порядок объектов в нем при представлении в тексте) теперь есть одна и ровно одна строка в jsonb_table, которая его представляет.

Теперь table_x это:

table_x_id (identity pk)
int1
int...
int8
text1_id (fk lookup)
text..._id (fk lookup)
text8_id (fk lookup)
jsonb1_id (fk lookup)
jsonb2_id (fk lookup)
hash1_bytea (based on int1, int2, text1_id, text2_id and jsonb1_id )
hash2_bytea (based on int3, int7, text3_id, jsonb1_id  and jsonb2_id )
hash3_bytea (based on int2, int5, text1_id and jsonb2_id )

Да, поддерживать text_table и jsonb_table проблематично, но это выполнимо, и table_x сейчас кажется довольно эффективным, способным быстро поддерживать несколько хэшей.

Кажется, я выполнил быструю и точную группировку по нескольким разновидностям группировок со многими полями.

На данный момент у меня есть два вопроса:

  1. Является ли мой подход разумным и относительно хорошо продуманным? Или есть лучший способ достичь моих целей?

  2. JSON в jsonb1 и jsonb2 на самом деле представляет собой просто массив менее часто используемых специальных пар ключ-значение. Однако данные в jsonb1 и jsonb2 нуждаются в ссылочной целостности с данными, поддерживаемыми в нормализованных реляционных таблицах. В таком случае не будет ли плохой идеей создать jsonb_child_table?

jsonb_child_table is:

jsonb_child_id (pk identity)
jsonb_id (fk to jsonb_table)
key_lookup_id (fk lookup)
value_lookup_id (fk lookup)

Опять же, хлопотно убедиться, что записи в jsonb_child_table являются правильными прорывами поля jsonb в jsonb_table, но, сделав это таким образом, я могу:

  • быстро поддерживать всю эту групповую информацию, обсуждавшуюся ранее
  • гарантировать хорошую ссылочную целостность
  • отчет о jsonb1 (например), используя поля в jsonb_child_table, упорядоченные (например) на основании метаданных (через соединение sql с использованием key_lookup_id), которые не хранятся в самом jsonb1.

Этот последний пункт, кажется, перекликается с тем, что я читал в другом месте в SO... что поддержка массива значений ключа в jsonb требует переосмысления... Если вы хотите обеспечить упорядочение пар, имейте ссылочную целостность и получайте данные быстрее, jsonb может быть плохим выбором. Однако в моем случае поддержка таблицы "заголовков" jsonb (с одним полем идентификатора внешнего ключа) позволяет быстро группировать разрозненные наборы (в table_x) пар значений. Поэтому я вижу преимущества в сохранении одних и тех же данных как в jsonb (для легкой группировки), так и в реальных таблицах (для RI и более быстрой и чистой отчетности).

Да, этот второй вопрос сам по себе достоин другого вопроса SO, но кажется, что вся эта куча взаимосвязана, поэтому я представляю все это здесь в одном (извините) длинном посте.

Заранее спасибо за отзыв!


person Wellspring    schedule 21.10.2019    source источник
comment
Ваш вопрос будет намного проще понять, если вы предоставите некоторые примеры входных данных и ожидаемый результат на основе этого в виде форматированного текста. . См. здесь несколько советов о том, как создавать красивые таблицы.   -  person a_horse_with_no_name    schedule 21.10.2019
comment
Спасибо за хорошую ссылку. Я изменил свои образцы данных в соответствии с вашим предложением.   -  person Wellspring    schedule 21.10.2019