Czy w MySQL kolejność kolumn w klauzuli WHERE wpływa na wydajność zapytań?


38

Mam problemy z wydajnością niektórych zapytań do bazy danych, które mają duże możliwe zestawy wyników.

Pytanie, o którym mowa, mam trzy ANDs w klauzuli WHERE

Czy kolejność klauzul ma znaczenie?

Tak jak w przypadku, jeśli najpierw wstawię klauzulę ASI_EVENT_TIME (ponieważ spowoduje to usunięcie większości wyników z którejkolwiek z klauzul).

Czy poprawi to czas działania zapytania?

PYTANIE:

SELECT DISTINCT  activity_seismo_info.* 
FROM `activity_seismo_info` 
WHERE 
    activity_seismo_info.ASI_ACTIVITY_ID IS NOT NULL  AND 
    activity_seismo_info.ASI_SEISMO_ID IN (43,44,...,259) AND 
    (
        activity_seismo_info.ASI_EVENT_TIME>='2011-03-10 00:00:00' AND 
        activity_seismo_info.ASI_EVENT_TIME<='2011-03-17 23:59:59'
    ) 

ORDER BY activity_seismo_info.ASI_EVENT_TIME DESC

OBJAŚNIJ zapytanie:

+----+-------------+---------+-------+---------------------------+--------------+---------+------+-------+-----------------------------+ 
| id | select_type | table   | type  | possible_keys             | key          | key_len | ref  | rows  | Extra                       |
+----+-------------+---------+-------+---------------------------+--------------+---------+------+-------+-----------------------------+ 
|  1 | SIMPLE      | act...o | range | act...o_FI_1,act...o_FI_2 | act...o_FI_1 | 5       | NULL | 65412 | Using where; Using filesort |
+----+-------------+---------+-------+---------------------------+--------------+---------+------+-------+-----------------------------+

Za pomocą:

PHP 5.2

MySQL 5.0.51a-3ubuntu5.4

Propel 1.3

Symfony 1.2.5


ORDER BY prawdopodobnie trwa tak długo. „Korzystanie z sortowania plików” może być bardzo wolne. Zauważyłem, że składanie zamówień w logice aplikacji jest DUŻO szybsze niż używanie ORDER BY.
maclema

Zadałem to samo pytanie jakiś czas temu (przed tą witryną) na stackoverflow. Sprawdź linki, aby uzyskać odpowiedzi, które tam otrzymałem. stackoverflow.com/questions/3805863/…
Scott

2
@maclema - chyba że twoja aplikacja działa na znacznie szybszym komputerze niż baza danych, twoje twierdzenie jest z pewnością nieprawdziwe, nie wspominając o bezsensownym obciążeniu całą logiką sortowania w twojej aplikacji. order bynależy do bazy danych.
Jack Douglas

Odpowiedzi:


24

Nie sądzę. Optymalizator zapytań powinien być wystarczająco sprytny.

Możesz spróbować zmienić kolejność klauzul WHERE i przekonać się, że WYJAŚNIENIA mówią ci to samo w każdym przypadku.


O tym, co można zrobić, aby zoptymalizować to zapytanie: Czy istnieje indeks w ASI_EVENT_TIME? (Myślę, że jest to najbardziej istotne dla tego zapytania, ponieważ sortujesz również wyniki za jego pomocą).

Czy istnieją indeksy w pozostałych dwóch polach (ASI_SEISMO_ID i ASI_ACTIVITY_ID)?

Byłoby pomocne, gdybyś opublikował strukturę tabeli.


Nigdy nie myślałem o stworzeniu indeksu czasów zdarzeń. Spróbuję to jutro na dev db i zobaczę, czy jest jakaś zauważalna różnica.
Patrick

@Patrick Zakładając, że wszystkie inne zapytania korzystające z tego indeksu porządkują tę datę w kolejności malejącej, należy zamówić klucz indeksu (activity_seismo_info.ASI_EVENT_TIME) również w kolejności malejącej.
Matt M

@MattM Nie wiedziałem, że MOŻESZ zamówić klucz indeksu. Niesamowite Jeśli zamówię klucz indeksu, czy to niekoniecznie zaszkodzi uporządkowaniu wydajności w przeciwnym kierunku niż to, że jest gorszy niż brak klucza indeksu?
Patrick

@Patrick Masz rację. Mój mózg utknął w krainie SQL Server. Możesz podać kolejność sortowania w MYSQL, która będzie analizować, ale jest ignorowana. Wszystkie indeksy są sortowane w porządku rosnącym w MYSQL. Przepraszam za zamieszanie.
Matt M

13

Z dokumentacji :

Jeśli tabela ma indeks wielokolumnowy, optymalizator może wykorzystać dowolny lewy przedrostek indeksu do znalezienia wierszy. Na przykład, jeśli masz indeks trzykolumnowy na (col1, col2, col3), masz indeksowane możliwości wyszukiwania na (col1), (col1, col2) i (col1, col2, col3).

MySQL nie może używać indeksu, jeśli kolumny nie tworzą prefiksu indeksu po lewej stronie.

Tak, powinien być taki sam, jak kolejność kolumn w indeksie złożonym .


4
Jeśli tabela ma indeks wielu kolumn, wybieranie kolumn z lewej ma znaczenie - ale kolejność, w której wybierasz, nie ma znaczenia. Więc jeśli masz indeks a, b, c i masz, WHERE c = 'foo' AND a = 'bar' AND b = 'foobar'a indeks nadal kwalifikuje się do użycia.
texelate

10

Nie, to nie ma znaczenia.

Optymalizator wykonuje kilka prostych przekształceń bezpośrednio po przeanalizowaniu kodu SQL - jest to jedna z nich.


8

GDZIE bar i bar

optymalizuje to samo co

GDZIE bar I foo

Jednak,

GDZIE nierówne # 1 ORAZ nierówne # 2

Nie można zoptymalizować obu części. Na przykład,

GDZIE MIĘDZY 1 a 3 ORAZ b> 17

nie może dobrze wykorzystać INDEKSU (a, b) lub INDEKSU (b, a)

Aby wyrazić to inaczej, najpierw używane są wszystkie testy „=” ORAZ razem w klauzuli WHERE, a następnie można obsłużyć jedno nie - „=” (IN, MIĘDZY,> itd.). Nie można skutecznie zoptymalizować więcej niż jednego.

Twoje zapytanie zawiera 3 takie klauzule.

Jak się okazuje, INDEKS (EVENT_TIME) jest prawdopodobnie najbardziej przydatny - pomoże w jednym z AND, i może być użyty do uniknięcia „sortowania plików” dla ORDER BY.

Jeśli nie ma zduplikowanych wierszy (dlaczego, u licha, miałby być?), Pozbądź się DISTINCT. To powoduje jeszcze większy wysiłek.

Zadawaj pytania POKAŻ TWORZENIE TABELI i STATUS POKAŻU TABELI, zadając pytania dotyczące wydajności.

Aktualizacja ... Nowsze wersje (np. MySQL 5.7) mogą, w niektórych sytuacjach, traktować IN( list of constants )prawie jak =. Aby grać bezpiecznie, trzymaj się tej kolejności (każda część jest opcjonalna):

  1. Dowolna liczba =.
  2. Niektóre INs.
  3. Co najwyżej jeden zakres.

1

MySQL, w którym dokument optymalizacji mówi:

Możesz mieć ochotę przepisać zapytania, aby przyspieszyć operacje arytmetyczne, a jednocześnie poświęcić czytelność. Ponieważ MySQL automatycznie wykonuje podobne optymalizacje , często można uniknąć tej pracy i pozostawić zapytanie w bardziej zrozumiałej i łatwej do utrzymania formie. Niektóre z optymalizacji przeprowadzanych przez MySQL są następujące:

  • ...

  • Dla każdej tabeli w sprzężenia, prostszy GDZIE jest skonstruowany , aby uzyskać szybki GDZIE oceny dla tabeli, a także pominąć wiersze jak najszybciej .

  • Zapytany jest każdy indeks tabeli i używany jest najlepszy indeks, chyba że optymalizator uzna, że bardziej efektywne jest użycie skanowania tabeli . Kiedyś zastosowano skan oparty na tym, czy najlepszy indeks obejmuje więcej niż 30% tabeli, ale stały procent nie określa już wyboru między użyciem indeksu a skanem. Optymalizator jest teraz bardziej złożony i opiera swoje oszacowanie na dodatkowych czynnikach, takich jak rozmiar tabeli, liczba wierszy i rozmiar bloku we / wy.

W ten sposób racjonalne jest, aby optymalizator zapytań pomijał kolejność JAK użyliśmy kolumn w zapytaniu (Nie tylko MySQL, ale SQL jest językiem deklaratywnym i musi robić to, co chcemy, a nie to, co chcemy).

Jednak nadal lubię mieć taki sam rodzaj kolumn klucza złożonego w zapytaniu, ale czasami jest to nieuniknione, na przykład, gdy używamy ORM lub ActiveRecord, w niektórych ramach, takich jak yii2, dostosowywanie kryteriów relacji zostanie dołączone na końcu warunek „włączony”, ale nadal potrzebujemy możliwości QueryBuilders w różnych częściach aplikacji.


-2

DOWOLNE pole, które jest używane w klauzulach WHERE / HAVING i ma wysoką selektywność (liczba unikalnych wartości / całkowita liczba rekordów> 10% ~ 20%) MUSI być indeksowane.

Jeśli więc ASI_EVENT_TIMEkolumna ma wiele możliwych wartości, najpierw zindeksuj je wszystkie. Następnie, jak powiedział @ypercube, spróbuj je zmienić i zobacz, co mówi WYJAŚNIENIE. Powinny być takie same.

Dodatkowo, chcesz spojrzeć na indeksowanie filtrów LIKE SQL . Chociaż nie jest to odpowiedź na pytanie, ale nadal dowiesz się, jak indeksowanie działa pod maską.

* Edycja: zapoznaj się z linkami podanymi poniżej w komentarzach, aby dowiedzieć się więcej o indeksowaniu.


8
-1 Indeksowanie każdej kolumny NIE jest najlepszą praktyką. Każdy indeks kosztuje Cię na wiele sposobów. Upewnij się, że wybierasz dobre indeksy, które zwykle składają się z wielu kolumn, zwykle w kolejności stosowanej selektywności i częstotliwości. Może to być SQL Server pochyły, ale informacji indeks jest nadal ważna: sqlskills.com/BLOGS/KIMBERLY/post/... .
Eric Humphrey - lotsahelp

@Eric Humphrey +1 Wyjaśnienie i link do strony Kimberly.
Matt M

jesteś w błędzie, mając indeks w kolumnie, czasami obniżasz wydajność w wybranych zapytaniach: mysqlperformanceblog.com/2007/08/28/… . NIGDY nie powinieneś używać zasady kciuka: czasem to działa, a czasem nie.
sumar

Zgadzam się. Jest to jednak ważne w przypadku, gdy selektywność wartości jest niska. Biorąc pod uwagę typ danych, z którego korzysta Patrick (autor tego pytania), którym jest DATETIME, zalecane jest indeksowanie. Zazwyczaj ten typ pola ma dość duży zestaw wartości, chyba że występuje dziwna sytuacja, gdy używa tylko kilku możliwych dat. * Przeredaguję moją odpowiedź powyżej, aby uzyskać bardziej jasne i prawidłowe oświadczenie.
Oko
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.