sql >> Databasteknik >  >> RDS >> PostgreSQL

Hur frågar man enkelt och effektivt efter kapslade relationer i SQL?

Som med alla frågor är den mest effektiva metoden "det beror på". Det finns många variabler i spel - antalet rader i tabeller, radlängder, om det finns index, RAM-minnet på servern, etc etc.

Det bästa sättet jag kan tänka mig att hantera den här typen av problem (tänker på underhållsbarhet och ett bra förhållningssätt till effektivitet) är att använda CTE, som låter dig skapa ett tillfälligt resultat och återanvända det resultatet genom hela din fråga. CTE:er använder nyckelordet WITH, och i huvudsak alias ett resultat som en tabell, så att du kan GÅ MED mot det flera gånger:

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)
;

Fördelarna med att göra det på detta sätt är:

  1. Varje CTE kan dra fördel av ett index på lämpliga JOIN-predikat och returnera resultat för just den delmängden snabbare, snarare än att exekveringsplaneraren försöker lösa en serie komplexa predikat
  2. CTE:erna kan underhållas individuellt, vilket gör det enklare att felsöka problem med delmängder
  3. Du bryter inte mot DRY-principen
  4. Om CTE har värde utanför frågan kan du flytta den till en lagrad procedur och referera till den istället


  1. SQL Server Oanvänd Index

  2. Hur ska jag redigera frågan för att förbättra prestandan och samtidigt behålla den befintliga strukturen?

  3. Hur man optimerar frågan om jag redan använder GIN-index

  4. mysql ny användaråtkomst nekad