PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Como consultar de forma simples e eficiente por relacionamentos aninhados no SQL?


Como em qualquer consulta, o método mais eficiente é "depende". Há muitas variáveis ​​em jogo - o número de linhas nas tabelas, os comprimentos das linhas, se existem índices, a RAM no servidor, etc etc.

A melhor maneira que consigo pensar em lidar com esse tipo de problema (pensando em manutenibilidade e uma abordagem ampla para eficiência) é usando CTEs, que permitem criar um resultado temporário e reutilizá-lo em toda a sua consulta. Os CTEs usam a palavra-chave WITH e, essencialmente, alias um resultado como uma tabela, para que você possa JOIN contra ela várias vezes:
WITH user_memberships AS (
    SELECT *
    FROM memberships
    WHERE user_id = ${id}
), user_apps AS (
    SELECT *
    FROM apps
    INNER JOIN user_memberships
        ON user_memberships.team_id = apps.team_id
), user_collections AS (
    SELECT *
    FROM collections
    INNER JOIN user_memberships
        ON user_memberships.team_id = collections.team_id
), user_webhooks AS (
    SELECT *
    FROM webhooks
    LEFT OUTER JOIN user_collections ON user_collections.id = webhooks.collection_id
    INNER JOIN user_memberships
        ON user_memberships.team_id = webhooks.team_id
        OR user_memberships.team_id = user_collections.team_id
)

SELECT events.* 
FROM events
WHERE app_id IN (SELECT id FROM user_apps)
OR collection_id IN (SELECT id FROM user_collections)
OR membership_id IN (SELECT id FROM user_memberships)
OR team_id IN (SELECT team_id FROM user_memberships)
OR user_id = ${id}
OR webhook_id IN (SELECT id FROM user_webhooks)
;

Os benefícios de fazer desta forma são:
  1. Cada CTE pode aproveitar um índice nos predicados JOIN apropriados e retornar resultados apenas para esse subconjunto mais rapidamente, em vez de fazer o planejador de execução tentar resolver uma série de predicados complexos
  2. Os CTEs podem ser mantidos individualmente, facilitando a solução de problemas com subconjuntos
  3. Você não está violando o princípio DRY
  4. Se o CTE tiver valor fora da consulta, você poderá movê-lo para um procedimento armazenado e fazer referência a ele