Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Jak sprawić, by MySQL używał INDEXu do zapytań o widok?

Jak sprawić, by MySQL używał indeksu dla zapytania widoku? Krótka odpowiedź zawiera indeks, z którego może korzystać MySQL.

W tym przypadku optymalnym indeksem jest prawdopodobnie indeks „pokrywający”:

... ON highscores (player, happened_in, score)

Jest prawdopodobne, że MySQL użyje tego indeksu, a EXPLAIN pokaże:"Using index" ze względu na WHERE player = 24 (predykat równości w wiodącej kolumnie w indeksie. GROUP BY happened_id (druga kolumna w indeksie) może pozwolić MySQL na optymalizację tego przy użyciu indeksu, aby uniknąć operacji sortowania. W tym score kolumna w indeksie pozwoli na pełne zaspokojenie zapytania z indeksu, bez konieczności odwiedzania (wyszukiwania) stron danych, do których odwołuje się indeks.

To szybka odpowiedź. Dłuższą odpowiedzią jest to, że MySQL jest bardzo mało prawdopodobne, aby używał indeksu z wiodącą kolumną happened_id dla zapytania widoku.

Dlaczego widok powoduje problemy z wydajnością

Jednym z problemów związanych z widokiem MySQL jest to, że MySQL nie „wypycha” predykatu z zapytania zewnętrznego w dół do zapytania widoku.

Twoje zewnętrzne zapytanie określa WHERE happened_in = 2006 . Optymalizator MySQL nie uwzględnia predykatu, gdy uruchamia wewnętrzne „zapytanie o widok”. To zapytanie dla widoku jest wykonywane osobno, przed zapytaniem zewnętrznym. Zestaw wyników z wykonania tego zapytania zostaje „zmaterializowany”; to znaczy, że wyniki są przechowywane jako pośrednia tabela MyISAM. (MySQL nazywa to "tablicą pochodną", a nazwa, której używają, ma sens, jeśli zrozumiesz operacje, które wykonuje MysQL.)

Najważniejsze jest to, że indeks zdefiniowany w happened_in nie jest używany przez MySQL podczas wykonywania zapytania tworzącego definicję widoku.

Po utworzeniu pośredniej „tabeli pochodnej”, WTEDY wykonywane jest zapytanie zewnętrzne, używając tej „tabeli pochodnej” jako źródła wierszy. Gdy to zewnętrzne zapytanie zostanie uruchomione, happened_in = 2006 orzeczenie jest oceniane.

Zwróć uwagę, że przechowywane są wszystkie wiersze z zapytania widoku, co (w twoim przypadku) jest wierszem dla KAŻDEJ wartości happened_in , a nie tylko ten, dla którego określono predykat równości w zewnętrznym zapytaniu.

Sposób przetwarzania zapytań widokowych może być „nieoczekiwany” przez niektórych i jest to jeden z powodów, dla których używanie „widoków” w MySQL może prowadzić do problemów z wydajnością w porównaniu ze sposobem przetwarzania zapytań widokowych przez inne relacyjne bazy danych.

Poprawa wydajności zapytania widoku z odpowiednim indeksem pokrywającym

Biorąc pod uwagę definicję widoku i zapytanie, najlepszą, jaką uzyskasz, będzie metoda dostępu „Używanie indeksu” dla zapytania widoku. Aby to uzyskać, potrzebujesz indeksu pokrycia, np.

... ON highscores (player, happened_in, score).

Prawdopodobnie będzie to najkorzystniejszy indeks (pod względem wydajności) dla istniejącej definicji widoku i istniejącego zapytania. player kolumna jest wiodącą kolumną, ponieważ istnieje predykat równości dla tej kolumny w zapytaniu widoku. happened_in kolumna jest następna, ponieważ masz operację GROUP BY na tej kolumnie, a MySQL będzie w stanie użyć tego indeksu do optymalizacji operacji GROUP BY. Uwzględniamy również score kolumna, ponieważ jest to jedyna inna kolumna, do której odwołuje się zapytanie. To sprawia, że ​​indeks jest indeksem „pokrywającym”, ponieważ MySQL może spełnić to zapytanie bezpośrednio ze stron indeksowych, bez konieczności odwiedzania jakichkolwiek stron w tabeli bazowej. I to jest tak dobre, jak wyjdziemy z tego planu zapytań:„Korzystanie z indeksu” bez „Korzystanie z sortowania plików”.

Porównaj wydajność z samodzielnym zapytaniem bez tabeli pochodnej

Możesz porównać plan wykonania swojego zapytania z widokiem z równoważnym samodzielnym zapytaniem:

SELECT player
     , MAX(score) AS highest_score
     , happened_in
 FROM highscores
WHERE player = 24
  AND happened_in = 2006
GROUP
   BY player
    , happened_in

Samodzielne zapytanie może również wykorzystywać indeks pokrywający, np.

... ON highscores (player, happened_in, score)

ale bez potrzeby materializowania pośredniej tabeli MyISAM.

Nie jestem pewien, czy którykolwiek z poprzednich stanowi bezpośrednią odpowiedź na zadane pytanie.

P:Jak sprawić, by MySQL używał INDEX do zapytań o widok?

O:Zdefiniuj odpowiedni INDEKS, którego może użyć zapytanie widoku.

Krótka odpowiedź to dostarczenie „indeksu obejmującego” (indeks obejmuje wszystkie kolumny, do których odwołuje się zapytanie widoku). Wiodące kolumny w tym indeksie powinny być kolumnami, do których odwołuje się predykat równości (w twoim przypadku kolumna player będzie wiodącą kolumną, ponieważ masz player = 24 predykat w zapytaniu. Ponadto kolumny, do których odwołuje się GRUPA WG, powinny być wiodącymi kolumnami w indeksie, co pozwala MySQL na optymalizację GROUP BY operacji, wykorzystując indeks zamiast operacji sortowania.

Kluczową kwestią jest tutaj to, że zapytanie widoku jest w zasadzie samodzielnym zapytaniem; wyniki z tego zapytania są przechowywane w pośredniej tabeli „pochodnej” (tabeli MyISAM, która jest tworzona po uruchomieniu zapytania względem widoku).

Korzystanie z widoków w MySQL niekoniecznie jest "złym pomysłem", ale zdecydowanie ostrzegam tych, którzy zdecydują się używać widoków w MySQL, aby byli ŚWIADOME, w jaki sposób MySQL przetwarza zapytania, które odwołują się do tych widoków. A sposób, w jaki MySQL przetwarza zapytania widoku różni się (znacząco) od sposobu, w jaki zapytania widoku są obsługiwane przez inne bazy danych (np. Oracle, SQL Server).



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. mysqli_stmt::bind_result():Liczba zmiennych wiązania nie odpowiada liczbie pól w przygotowanej instrukcji

  2. MySQL:ALTER TABLE, jeśli kolumna nie istnieje

  3. AKTYWATORY, które powodują niepowodzenie INSERT? Możliwy?

  4. Połącz się zdalnie z MySQL

  5. używanie wartości null w przygotowanym oświadczeniu mysqli