JAK vs ZAWIERA na SQL Server

210

Które z poniższych zapytań jest szybsze (LIKE vs CONTAINS)?

SELECT * FROM table WHERE Column LIKE '%test%';

lub

SELECT * FROM table WHERE Contains(Column, "test");
użytkownik667429
źródło
12
Zaakceptuj odpowiedź?
AgentFire,
7
Nie był włączony od lat, człowieku.
Chris

Odpowiedzi:

174

Drugi (zakładając, że masz na myśli CONTAINSi faktycznie umieścisz go w prawidłowym zapytaniu) powinien być szybszy, ponieważ może używać jakiejś formy indeksu (w tym przypadku indeksu pełnotekstowego). Oczywiście ta forma zapytania jest dostępna tylko wtedy, gdy kolumna ma indeks pełnotekstowy. Jeśli tak nie jest, dostępna jest tylko pierwsza forma.

Pierwsze zapytanie, używając LIKE, nie będzie w stanie użyć indeksu, ponieważ zaczyna się od znaku wieloznacznego, więc zawsze będzie wymagało pełnego skanowania tabeli.


CONTAINSZapytanie powinno być:

SELECT * FROM table WHERE CONTAINS(Column, 'test');
Damien_The_Unbeliever
źródło
@edze - masz na myśli tę samą stronę, do której prowadzi już moja pierwsza wzmianka CONTAINS? Co z tego? Oryginalna forma pytania miała, Column CONTAIN("%test%",Column)>0która nie była blisko ważna. To nadal nie jest całkowicie poprawne.
Damien_The_Unbeliever
To pomogło nam uporządkować zapytanie dotyczące SharePoint. Zdobądź kolejną odznakę Great Answer.
ouflak 4.04.17
14

Po uruchomieniu obu zapytań w wystąpieniu programu SQL Server 2012 mogę potwierdzić, że pierwsze zapytanie było najszybsze w moim przypadku.

Zapytanie ze LIKEsłowem kluczowym pokazało skanowanie indeksu klastrowego.

CONTAINSMiał również skanowanie indeksu klastrowego z dodatkowych operatorów do pełnego meczu tekstu i scalanie przyłączyć.

Plan

MI C.
źródło
8
Strony liścia indeksu klastrowanego tabelą. LIKEZapytanie z wiodącą zamiennika nie będzie w stanie efektywnie wykorzystać część indeksu. Będzie musiał po prostu zeskanować całość. Chociaż niewątpliwie mogą zaistnieć pewne okoliczności, w których pełne skanowanie CI działa lepiej niż zapytanie przy użyciu indeksu pełnotekstowego (być może, jeśli na przykład pasuje bardzo duża liczba wierszy), będzie to w dużej mierze wyjątek, a nie jakakolwiek ogólna reguła, którą „można potwierdzić „.
Martin Smith
Cóż, patrzę na rzeczywisty plan wykonania, który pobiera ponad 200 000 rekordów. Umieszczając oba zapytania w pakiecie, oba skanowały indeks klastrowany, ale dodatkowo zapytanie „ZAWIERA” ma dodatkowy koszt PEŁNEGO MECZU TEKSTOWEGO i ŁĄCZENIA POŁĄCZENIA.
MI C
Jeśli wybierze połączenie scalające, SQL Server szacuje, że więcej niż x% wierszy będzie pasować do predykatu. (Gdzie X = punkt krytyczny ). W takim razie wyobrażam sobie, że oba mogłyby się skończyć dość równo. Koszty przedstawione w planie wykonania są jedynie szacunkami (nawet w rzeczywistym planie). Chociaż w planie FT są dodatkowi operatorzy planu wykonania, ma on pewne zalety. Łączenie scalające może zatrzymać się przed końcem skanowania, gdy skończą się wyniki FT, a także nie musi oceniać LIKE.
Martin Smith
1
Uruchomiłem podobne zapytanie, aby sprawdzić plan wykonania w SQL 2012 i dało mi to Indeks wyszukiwania. Może w tym przykładzie stół był prawie pusty. W niektórych przypadkach sql używa skanu indeksu w bardzo małej tabeli, aby użyć indeksu, ponieważ jest szybszy.
Juan
8

Myślę, że CONTAINSzajęło to więcej czasu i było używane, Mergeponieważ w zapytaniu miałeś myślnik („-”) adventure-works.com.

Myślnik jest słowem przerywanym, więc CONTAINSprzeszukiwany indeks pełnotekstowy adventureszukał, works.coma następnie wyszukiwał i łączył wyniki.

Omri Valfer
źródło
8

Spróbuj także zmienić z tego:

    SELECT * FROM table WHERE Contains(Column, "test") > 0;

Do tego:

    SELECT * FROM table WHERE Contains(Column, '"*test*"') > 0;

Pierwszy znajdzie rekordy o wartościach takich jak „ to test ”, a „ przypadek testowy to plan ”.

Ten drugi znajdzie również rekordy o wartościach takich jak „ testuję to ” i „ to jest największe ”.

nieznany z nazwiska
źródło
4
Czy umieszczenie gwiazdki przed i po wyszukiwanym terminie działa? Czytając dokumentację CONTAINS, wspomina tylko o użyciu terminów takich jak „test *”, a nie terminów takich jak „ test” i niepełnego wyszukiwania podciągów jak „* test ”. Jednak tego nie próbowałem.
matt forsythe
5
Jeśli przeczytasz dokumentację ZAWIERA ( docs.microsoft.com/en-us/sql/t-sql/queries/… ), obsługiwane jest tylko wyszukiwanie prefiksów. Próbowałem tego eksperymentalnie wiele razy i nie można znaleźć „to jest największe” (w SQL Sever) z Contains (kolumna, „ test ”)
cl0rkster 15.09.17