PostgreSQL faktycznie obsługuje indeksy GIN w kolumnach tablicowych. Niestety, nie wydaje się być użyteczny dla indeksów NOT ARRAY[...] <@ indexed_col
, a indeksy GIN
nie nadają się do często aktualizowanych tabel.
Demo:
CREATE TABLE arrtable (id integer primary key, array_column integer[]);
INSERT INTO arrtable(1, ARRAY[1,2,3,4]);
CREATE INDEX arrtable_arraycolumn_gin_arr_idx
ON arrtable USING GIN(array_column);
-- Use the following *only* for testing whether Pg can use an index
-- Do not use it in production.
SET enable_seqscan = off;
explain (buffers, analyze) select count(id)
from arrtable
where not (ARRAY[1] <@ arrtable.array_column);
Niestety, to pokazuje, że jak napisane, że nie można korzystać z indeksu. Jeśli nie negujesz warunku, możesz go użyć, aby wyszukać i policzyć wiersze, które zawierają element wyszukiwania (usuwając NOT
).
Możesz użyć indeksu do zliczania wpisów, które do zawierają wartość docelową, a następnie odejmij ten wynik od liczby wszystkich wpisów. Ponieważ count
, wszystkie wiersze w tabeli są dość powolne w PostgreSQL (9.1 i starsze) i wymaga skanowania sekwencyjnego, będzie to wolniejsze niż bieżące zapytanie. Jest możliwe, że na 9,2 skanowanie indeksu można używać tylko policzyć wiersze jeśli masz indeks B-drzewo na id
, w tym przypadku może to być rzeczywiście OK:
SELECT (
SELECT count(id) FROM arrtable
) - (
SELECT count(id) FROM arrtable
WHERE (ARRAY[1] <@ arrtable.array_column)
);
To gwarantowany wykonać gorzej niż Oryginalna wersja dla Pg 9.1 i poniżej, ponieważ oprócz seqscan twój oryginał wymaga tego również potrzebuje potrzebuje skanowania indeksu GIN. Przetestowałem to teraz w wersji 9.2 i wydaje się, że używa on indeksu do liczenia, więc warto go zbadać w wersji 9.2. Z jakiegoś mniej trywialny danych manekina:
drop index arrtable_arraycolumn_gin_arr_idx ;
truncate table arrtable;
insert into arrtable (id, array_column)
select s, ARRAY[1,2,s,s*2,s*3,s/2,s/4] FROM generate_series(1,1000000) s;
CREATE INDEX arrtable_arraycolumn_gin_arr_idx
ON arrtable USING GIN(array_column);
pamiętać, że indeks GIN jak to będzie spowolnić aktualizacje w dół dużo, i jest dość powolny, aby utworzyć w pierwszej kolejności. Nie nadaje się do tabel, które w ogóle są aktualizowane - na przykład Twój stół.
Gorsze, zapytanie za pomocą tego indeksu zajmuje do dwukrotności długość pierwotnego zapytania i co najwyżej połowę długości na tym samym zbiorze danych. To najgorsze w przypadku, gdy indeks nie jest bardzo selektywny, jak ARRAY[1]
- 4s vs 2s dla pierwotnego zapytania. Tam, gdzie indeks jest wysoce selektywny (tzn. Nie ma wielu dopasowań, takich jak ARRAY[199]
), trwa około 1,2 sekundy w porównaniu z oryginalnymi 3 znakami. Tego wskaźnika po prostu nie warto mieć dla tego zapytania.
Lekcja tutaj? Czasami właściwą odpowiedzią jest wykonanie sekwencyjnego skanowania.
Od tego nie zrobi dla swoich stóp hit, albo utrzymać zmaterializowanej widok z wyzwalaczem jak sugeruje @debenhur lub próbować odwrócić tablicę się lista parametrów, że pozycja nie nie mają więc może używać indeksu GiST, jak sugeruje @maniek.
Nie jestem pewien, ale myślę, że indeks GIN na table.array_column pomoże przyspieszyć ten proces. Aby dowiedzieć się, musisz uruchomić EXPLAIN. Zobacz tutaj: http://dba.stackexchange.com/a/27505/1822 –
Ciężko będzie zrobić to wydajnie w postgresie, gdy stół stanie się duży. indeks ginu pomoże tylko podczas testowania "zawartego w", w przeciwieństwie do "nie zawartego" w twoim predykacie. Jeśli nie jest ważne, aby liczba była dokładna w 100%, możesz spróbować zapisać ją w warstwie aplikacji z pewnym TTL. Jeśli twoja szybkość zapisu w tabeli nie jest zbyt wysoka, możesz rozsądnie użyć wyzwalaczy do aktualizacji kolejnej tabeli zawierającej aktualne liczby. – dbenhur
Najlepiej pokazać swoją wersję i 'wyjaśnić analizę'; zobacz http://stackoverflow.com/tags/postgresql-performance/info –