Вопрос проектирования для таблицы со слишком большим количеством объединений ИЛИ отношений полиморфизма c в Postgres 11.7 - PullRequest
1 голос
/ 28 мая 2020

Мне дали таблицу, которую я не знаю, как ее спроектировать. Я надеюсь на некоторые дизайнерские предложения или указатели в правильном направлении. Таблица называется edge и предназначена для хранения некоторых трассировок событий и идентификаторов, которые связываются с хостом из возможных таблиц поиска. Оставляя все, кроме идентификаторов, вот что содержит таблица, все UUID:

ID
InvID
OrgID
FacilityID

FromAssemblyID
FromAssociatedTo
FromAssociatedToID
FromClinicID
FromFacilityDepartmentID
FromFacilityID
FromFacilityLocationID
FromScanAtFacilityID
FromScanID
FromSCaseID
FromSterilizerLoadID
FromWasherLoadID
FromWebUserID

ToAssemblyID
ToAssociatedTo
ToAssociatedToID
ToClinicID
ToFacilityDepartmentID
ToFacilityID
ToFacilityLocationID
ToNodeDTS
ToScanAtFacilityID
ToScanID
ToSCaseID
ToSterilizerLoadID
ToUserName
ToWasherLoadID
ToWebUserID

Это огромное количество идентификаторов, к которым можно присоединиться. Я помню, как читал, что планировщик Postgres сдается, когда у вас есть дюжина + присоединений. Идея состоит в том, что существует так много вариантов для изучения, что время планирования может быстро превзойти время запроса. Если вы свести это к минимуму, ссылки «от» и «к» всегда будут иметь только одно ключевое значение во всех этих полях. Итак, реализовано как полиморфные / беспорядочные связи, что-то вроде этого:

ID
InvID
OrgID
FacilityID
FromID
FromType
ToID
ToType
ToWebUserID

Эта таблица будет огромной, поэтому скорость будет учитываться.

Я поддержал автора не использовать полиморфный c дизайн, хотя привлекательность очевидна. (Мне нравится книга Карвина SQL Antipatterns .) Но теперь, столкнувшись с почти тремя дюжинами идентификаторов, я немного озадачен.

Есть ли общее решение такого рода проблем? А именно, где у вас есть такая центральная таблица с подключениями к большому количеству возможных таблиц? У меня нет опыта работы с хранилищами данных, но это выглядит примерно так. (Автор этой таблицы читал книги Кимбалла, но не реализовал никаких реализаций хранилищ данных.)

Важно: мы используем JOIN для поиска связанных значений, которые могут измениться, мы не , используя его для изменения размера набора результатов. Просто представьте, что это всегда будет LEFT JOIN.

Имея это в виду, я подумал о том, чтобы пропустить присоединение по идентификаторам From и To и вместо этого использовать вызовы пользовательских функций для просмотра вверх требуемые значения из связанных таблиц. как (псевдокод)

GetUserName(uuid) : citext
...and os on for other values of interest in this and other tables...

Функция вернет '', когда UUID равен 0000et c.

Я понимаю, что это не самый четкий вопрос в истории ТАК, и я надеюсь на указатели в плодотворном направлении.

1 Ответ

0 голосов
/ 28 мая 2020

Это попахивает «преждевременной оптимизацией» (которая является источником зла), основанной на чем-то, что вы «помните, читали», так что, возможно, вам поможет некоторое понимание оптимизации соединения.

Одно практическое правило, которое я Следуйте этим вопросам, чтобы моделировать вещи, чтобы ваши запросы стали простыми и естественными. Опыт показывает, что это часто приводит к хорошей производительности.

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

SELECT ...
FROM fact
   JOIN dim1 ON fact.dim1_id = dim1.id
   JOIN dim2 ON fact.dim3_id = dim2.id
   JOIN dim3 ON fact.dim3_id = dim3.id
   ...
WHERE dim1.col1 = ...
  AND dim2.col2 BETWEEN ... AND ...
  AND dim3.col3 < ...
  ...

Теперь PostgreSQL по умолчанию будет учитывать только все перестановки соединений первых восьми таблиц (join_collapse_limit), а остальные таблицы просто объединяются в том порядке, в котором они появляются в query.

Более того, если количество таблиц достигает порогового значения 12 (geqo_threshold), берет на себя geneti c оптимизатор запросов , компонент, который имитирует эволюцию путем мутации и выживание наиболее приспособленных со случайно выбранными планами выполнения (действительно!) и, следовательно, не всегда дает один и тот же план выполнения для одного и того же запроса.

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

Тогда вы должны установить geqo = off чтобы отключить оптимизатор запросов geneti c.

Если вы разрабатываете свои запросы в соответствии с этими принципами, вы сможете получить хорошие планы выполнения без нарушения модели данных.

...