5

Obecnie mam następujące:Szybsze wyszukiwanie rekordów, w których 1. znak pola nie pasuje [A-Za-z]?

User (id, fname, lname, deleted_at, guest) 

mogę zapytać o listę użytkownika poprzez ich fname inicjału tak:

User Load (9.6ms) SELECT "users".* FROM "users" WHERE (users.deleted_at IS NULL) AND (lower(left(fname, 1)) = 's') ORDER BY fname ASC LIMIT 25 OFFSET 0 

ta jest szybka dzięki następującym index:

CREATE INDEX users_multi_idx 
    ON users (lower(left(fname, 1)), fname) 
    WHERE deleted_at IS NULL; 

Co chcę teraz zrobić, to móc zapytać o wszystkich użytkowników, którzy nie zaczynają od litery AZ. Mam to działało tak:

SELECT "users".* FROM "users" WHERE (users.deleted_at IS NULL) AND (lower(left(fname, 1)) ~ E'^[^a-zA-Z].*') ORDER BY fname ASC LIMIT 25 OFFSET 0 

Ale problemem jest to zapytanie jest bardzo powolny i nie wydaje się być przy użyciu indeksu, aby przyspieszyć pierwsze zapytanie. Jakieś sugestie na temat tego, w jaki sposób mogę sprawić, że 2. zapytanie (nie a-z) jest szybsze?

Używam PostgreSQL 9.1 z szyn 3,2

Dzięki

+0

Dziękujemy za przedstawienie wersji. Pomocne może być wklejenie opcji EXPLAIN ANALYZE w obu zapytaniach do http: //explain.depesz.com/i powiązane z nimi tutaj (powinieneś to zrobić dla wszystkich pytań dotyczących wydajności), chociaż w tym przypadku jest dość jasne, że pierwszy używa indeksu, którego drugi nie może. –

+1

Proszę połączyć się z wcześniejszymi, pokrewnymi pytaniami, jeśli już istnieją, ułatwia to odpowiadanie. –

Odpowiedz

3

Aktualizacja odpowiedź
Preceding question here.

Mój pierwszy pomysł pomysł (indeks z text_pattern_ops) nie działa z wyrażeń regularnych moje testy. Lepiej przepisać zapytanie do:

SELECT * 
FROM users 
WHERE deleted_at IS NULL 
WHERE lower(left(fname, 1)) < 'a' COLLATE "C" OR lower(left(fname, 1)) > 'z' COLLATE "C" 
ORDER BY fname 
LIMIT 25 OFFSET 0;

Poza tym od wyrażenia te są na ogół szybciej, wyrażenie regularne miał również litery w nim, które nie pasują do indeksu z lower(). A ciągnące się znaki były bezcelowe w porównaniu do pojedynczego znaku.

i używania tego indeksu:

CREATE INDEX users_multi_idx 
ON users (lower(left(fname, 1)) COLLATE "C", fname) 
WHERE deleted_at IS NULL;

COLLATE "C" część jest opcjonalna i tylko przyczynia bardzo niewielki przyrost wydajności. Jego celem jest zresetowanie reguł sortowania do domyślnego sortowania posix, który po prostu używa kolejności bajtów i generalnie jest szybszy. Przydatne, gdy reguły sortowania nie są istotne.

Jeśli utworzysz indeks przy pomocy, mogą z niego korzystać tylko zapytania pasujące do sortowania. Więc możesz po prostu pominąć to, aby uprościć rzeczy, jeśli wydajność nie jest najważniejszym wymogiem.

+1

Oczywiście musi to być 'OR', a nie' AND'. –

+0

Dzięki, ale wyniki są błędne: ActionView :: Szablon :: Błąd (PG :: Błąd: BŁĄD: kolumna "a" nie istnieje LINIA 1: ... usunięty_at IS NULL) I (dolny (lewy (fname, 1)) <"a" COLLAT ... – AnApprentice

+1

@ColdTree: Zastąp podwójne cudzysłowy wokół "a" pojedynczymi cytatami: -> ** '' a'' **. –

2

Jako alternatywę dla ogólnego rozwiązania @ ErwinBrandstetter, PostgreSQL obsługuje partial indexes. Można powiedzieć:

CREATE INDEX users_nonalphanumeric_not_deleted_key 
ON users (id) 
WHERE (users.deleted_at IS NULL) AND (lower(left(fname, 1)) ~ E'^[^a-zA-Z].*'); 

Indeks ten nie pomoże w przypadku innych wyszukiwań, ale będzie to wcześniej obliczyć odpowiedź dla tego konkretnego zapytania. Technika ta jest często przydatna w przypadku zapytań, które zwracają mały, predefiniowany podzbiór z dużo większej tabeli, ponieważ wynikowy indeks nie uwzględnia znacznej większości tabeli i zawiera tylko interesujące wiersze.

+2

Należy pamiętać, że zapytanie będzie musiało używać warunku indeksu niemal dosłownie; Planer zapytań nie jest bardzo inteligentny w dopasowywaniu równoważnych warunków. Na przykład, jeśli odwrócisz dwie klauzule wokół 'ORAZ ', planista prawdopodobnie nie użyje indeksu. Uważam, że pomocne jest zawarcie warunku indeksu w funkcji SQL, a następnie użycie tej funkcji SQL wszędzie tam, gdzie chcę odnosić się do indeksu, ponieważ ułatwia to planantowi dopasowanie do dwóch. –

Powiązane problemy