эффективно сгруппировать много полей, включая большой текст и JSONB - PullRequest
1 голос
/ 21 октября 2019

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

Предположим, у меня есть таблица 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, используя вызовы digest () в триггере вставки / обновления. (Идея заключалась в том, чтобы преобразовать все соответствующие поля в моей группировке в строки, объединить их вместе и запустить хеш для результирующей строки.)

Теперь table_x is:

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:

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:

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 может быть плохим выбором. Однако в случае my ведение таблицы заголовков jsonb (с одним полем идентификатора внешнего ключа) позволяет быстро группировать разнородные коллекции (в table_x) пар значений. Поэтому я вижу преимущества в поддержании одинаковых данных как в jsonb (для легкой группировки), так и в реальных таблицах (для RI и более быстрых, более чистых отчетов).

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

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

...