Ja, överlappningsoperator &&
skulle kunna använda ett GIN-index på arrayer
. Mycket användbart för frågor den här för att hitta rader med en given person (1
) bland en rad skådespelare:
SELECT * FROM eg_assoc WHERE actors && '{1}'::int[]
Men , logiken i din fråga är tvärtom, letar efter alla personer som är listade i arrayerna i eg_assoc
. Ett GIN-index är nej hjälp här. Vi behöver bara btree-indexet för PK person.id
.
Rätta frågor
Grunderna:
Följande frågor bevarar ursprungliga arrayer exakt som givna , inklusive möjliga dubbletter av element och ursprunglig ordning av element. Fungerar för endimensionella arrayer . Ytterligare dimensioner viks till en enda dimension. Det är mer komplicerat att bevara flera dimensioner (men fullt möjligt):
WITH ORDINALITY
i Postgres 9.4 eller senare
SELECT aid, actors
, ARRAY(SELECT name
FROM unnest(e.actors) WITH ORDINALITY a(id, i)
JOIN eg_person p USING (id)
ORDER BY a.i) AS act_names
, benefactors
, ARRAY(SELECT name
FROM unnest(e.benefactors) WITH ORDINALITY b(id, i)
JOIN eg_person USING (id)
ORDER BY b.i) AS ben_names
FROM eg_assoc e;
LATERAL
frågor
För PostgreSQL 9.3+ .
SELECT e.aid, e.actors, a.act_names, e.benefactors, b.ben_names
FROM eg_assoc e
, LATERAL (
SELECT ARRAY( SELECT name
FROM generate_subscripts(e.actors, 1) i
JOIN eg_person p ON p.id = e.actors[i]
ORDER BY i)
) a(act_names)
, LATERAL (
SELECT ARRAY( SELECT name
FROM generate_subscripts(e.benefactors, 1) i
JOIN eg_person p ON p.id = e.benefactors[i]
ORDER BY i)
) b(ben_names);
db<>fiol här
med ett par varianter.
Gammal sqlfiddle
Subtil detalj:Om en person inte hittas släpps den bara. Båda dessa frågor genererar en tom array ('{}'
) om ingen person hittas för hela arrayen. Andra frågestilar skulle returnera NULL
. Jag lade till varianter till fiolen.
Korrelerade underfrågor
För Postgres 8.4+ (där generate_subsrcipts()
introducerades):
SELECT aid, actors
, ARRAY(SELECT name
FROM generate_subscripts(e.actors, 1) i
JOIN eg_person p ON p.id = e.actors[i]
ORDER BY i) AS act_names
, benefactors
, ARRAY(SELECT name
FROM generate_subscripts(e.benefactors, 1) i
JOIN eg_person p ON p.id = e.benefactors[i]
ORDER BY i) AS ben_names
FROM eg_assoc e;
Kan fortfarande prestera bäst, även i Postgres 9.3.
The ARRAY
konstruktör
är snabbare än array_agg()
. Se:
Din misslyckade fråga
frågan från @a_horse verkar att göra jobbet, men det är opålitligt, vilseledande, potentiellt felaktigt och onödigt dyrt.
-
Proxy cross join på grund av två orelaterade joins. Ett lömskt antimönster. Se:
Fixat ytligt med
DISTINCT
iarray_agg()
för att eliminera de genererade dubbletterna, men det är verkligen att sätta läppstift på en gris. Det eliminerar också dubbletter i originalet eftersom det är omöjligt att se skillnad vid det här laget - vilket är potentiellt felaktigt. -
Uttrycket
a_person.id = any(eg_assoc.actors)
fungerar , men eliminerar dubbletter från resultatet (händer två gånger i den här frågan), vilket är fel om inget annat anges. -
Ursprunglig ordning av matriselement bevaras inte . Detta är knepigt i allmänhet. Men det förvärras i den här frågan, eftersom aktörer och välgörare multipliceras och görs åtskilda igen, vilket garanterar godtycklig ordning.
-
Inga kolumnalias i den yttre
SELECT
resultera i dubbla kolumnnamn, vilket gör att vissa klienter misslyckas (fungerar inte i fiolen utan alias). -
min(actors)
ochmin(benefactors)
är värdelösa. Normalt skulle man bara lägga till kolumnerna iGROUP BY
istället för att falska samman dem. Meneg_assoc.aid
är PK-kolumnen ändå (som täcker hela tabellen iGROUP BY
), så det är inte ens nödvändigt. Baraactors, benefactors
.
Att samla hela resultatet är bortkastad tid och ansträngning till att börja med. Använd en smartare fråga som inte multiplicerar basraderna, då behöver du inte aggregera dem igen.