2011-12-21 13 views
14

Mam DB z kilku pólSQLite: czy LIKE 'searchstr%' powinien używać indeksu?

word_id — INTEGER PRIMARY_KEY 
word — TEXT 
... 

..i ~ 150k wierszy.

Ponieważ jest to słownik, szukam słowa z maską 'search_string%' używając LIKE. Kiedyś pracował dobrze, biorąc 15 ms, aby znaleźć pasujące wiersze. Tabela ma indeks dla pola 'word'. Niedawno zmodyfikowałem tabelę (niektóre pola tej tabeli, które są poza zakresem) i coś się wydarzyło - zajmuje to 400 ms, aby wykonać zapytanie, więc rozumiem, że teraz nie korzysta z indeksu. Proste zapytanie z = zamiast podobnym pokazuje wynik 10 ms. Czy ktoś ma pomysł, co się tutaj dzieje?

+0

Myślę, że tak, prawdopodobnie chcesz spojrzeć na b-drzewo, ponieważ b-drzewo jest wydajne w zapytaniu o zakres i podobne porównanie. – Jasonw

+0

Hmm, nie indeksu przypuszczam tworzenie b-drzewa? Masz na myśli, że sam powinienem stworzyć b-drzewo? – nikans

+0

Czy% zawsze pojawia się tylko na końcu wyszukiwanego hasła, a nie na początku? – mikel

Odpowiedz

25

W tym przypadku nie można bezpiecznie użyć indeksu. Naiwny wdrożenie byłoby przekształcić następująco:

... WHERE word LIKE 'search_string%'

do

... WHERE word >= 'search_string' AND word < 'search_strinh'

przez zwiększający ostatni znak łańcucha wyszukiwania. Operatory o wartości większej niż i niższej mogą używać indeksu, gdzie LIKE nie może.

Niestety, to nie zadziała w ogólnym przypadku. Operator LIKE nie rozróżnia wielkości liter, co oznacza, że ​​'a' LIKE 'A' ma wartość true. Powyższa transformacja złamałaby łańcuch wyszukiwania literami wielkimi literami.

Jednak w niektórych przypadkach wiesz,, że wielkość liter nie ma znaczenia dla konkretnej kolumny, a powyższa transformacja jest bezpieczna. W takim przypadku masz dwie opcje.

  1. Użyj sekwencji zestawiania NOCASE w indeksie, który obejmuje to konkretne pole.
  2. zmienić zachowanie operatora LIKE całego programu uruchamiając PRAGMA case_sensitive_like = ON;

Każde z tych zachowań pozwoli SQLite transparentne zrobić powyższej transformacji dla Ciebie; po prostu nadal używasz LIKE jak zawsze, a SQLite przerobi zapytanie bazowe, aby użyć indeksu.

Możesz przeczytać więcej o "Optymalizacji LIKE" na SQLite Query Optimizer Overview page.

+1

Cholera! W powyższym wątku wspomniałem, że używam niektórych parametrów podczas tworzenia indeksów (które działały) po raz ostatni. Tak więc był to "NIELENIE KOLLANU". Spędziłem około 6 godzin bezskutecznie. Dobry link, też to przeczytałem, ale wygląda na to, że po prostu zniknęło z mojej uwagi. Dziękuję, Homer! Właśnie uratowałeś mnie, bóg wie, ile czasu. – nikans

+0

Myślę, że masz na myśli 'PRAGMA case_sensitive_like = ON;' Tak jak powiedziałeś, 'LIKE' jest domyślnie niewrażliwe na wielkość znaków. Z artykułu, do którego linkujesz: "Optymalizacja LIKE może wystąpić, jeśli kolumna o nazwie po lewej stronie operatora jest indeksowana przy użyciu wbudowanej sekwencji sortowania BINARY, a case_sensitive_like jest włączona." –

+0

Ah, prawda. Naprawię to. Dzięki! –

Powiązane problemy