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

Wydajność MySQL VIEW dla tabel w połączeniu z UNION ALL

Zgadzam się ze wszystkimi punktami doskonałej odpowiedzi Billa Karwina.

P: Czy normalną praktyką jest tworzenie widoku dla omawianego zapytania składającego i używanie go w moich sprzężeniach, podselekcji itp.?

O: W przypadku MySQL bardziej normalną praktyką jest unikanie używania instrukcji „CREATE VIEW”.

P: Pod względem wydajności - czy będzie gorszy, równy czy lepszy w porównaniu do zwykłego wstawiania do złączeń, podselekcji itp.?

O: Odwoływanie się do obiektu widoku będzie miało taką samą wydajność jak równoważny widok wbudowany.

(Może być trochę więcej pracy, aby wyszukać obiekt widoku, sprawdzić uprawnienia, a następnie zastąpić odwołanie do widoku przechowywanym kodem SQL, w porównaniu do wysyłania instrukcji, która jest tylko maleńka dłuższa. różnice są nieznaczne.)

P: Czy są jakieś wady posiadania widoku w tym przypadku?

O: Największą wadą jest sposób, w jaki MySQL przetwarza widok, niezależnie od tego, czy jest on przechowywany, czy wbudowany. MySQL zawsze uruchomi zapytanie widoku i zmaterializuje wyniki tego zapytania jako tymczasową tabelę MyISAM. Ale nie ma różnicy, czy definicja widoku jest przechowywana, czy jest zawarta w tekście. (Inne systemy RDBMS przetwarzają widoki znacznie inaczej niż MySQL).

Jedną dużą wadą widoku jest to, że predykaty z zapytania zewnętrznego NIGDY nie są wpychane do zapytania widoku. Za każdym razem, gdy odwołujesz się do tego widoku, nawet z zapytaniem o pojedynczą wartość identyfikatora, MySQL uruchomi zapytanie widoku i utworzy tymczasową tabelę MyISAM (bez żadnych indeksów), a NASTĘPNIE MySQL uruchomi zewnętrzne zapytanie względem tego tymczasowego Tabela MyISAM.

Tak więc, jeśli chodzi o wydajność, pomyśl o odwołaniu do widoku na równi z „CREATE TEMPORARY TABLE t (cols) ENGINE=MyISAM " i "INSERT INTO t (cols) SELECT ... ".

MySQL w rzeczywistości odnosi się do widoku wbudowanego jako „tabeli pochodnej”, a ta nazwa ma wiele sensu, gdy zrozumiemy, co MySQL z nim robi.

Osobiście wolę nie używać instrukcji „CREATE VIEW”. Największą wadą (jak ja to widzę) jest to, że "ukrywa" wykonywany SQL. Dla przyszłego czytelnika odniesienie do widoku wygląda jak tabela. A potem, kiedy zaczyna pisać instrukcję SQL, odwołuje się do widoku jak do tabeli, co jest bardzo wygodne. Potem postanawia, że ​​dołączy do tego stołu, z innym odniesieniem do niego. (Dla drugiego odniesienia, MySQL również uruchamia to zapytanie ponownie i tworzy kolejną tymczasową (i nieindeksowaną) tabelę MyISAM. A teraz jest na tym operacja JOIN. A następnie zostaje dodany predykat „WHERE view.column ='foo'” na zewnętrznym zapytaniu.

Kończy się to „ukrywaniem” najbardziej oczywistej poprawy wydajności, przesuwając ten predykat do zapytania widoku.

A potem pojawia się ktoś i decyduje, że stworzy nowy widok, który odwołuje się do starego. Potrzebuje tylko podzbioru wierszy i nie może modyfikować istniejącego widoku, ponieważ może to spowodować uszkodzenie, więc tworzy nowy widok... CREATE VIEW myview FROM publicview p WHERE p.col ='foo'.

A teraz odwołanie do myview spowoduje najpierw uruchomienie zapytania publicview, utworzenie tymczasowej tabeli MyISAM, a następnie uruchomienie zapytania myview, utworzenie kolejnej tymczasowej tabeli MyISAM, względem której będzie wykonywane zapytanie zewnętrzne.

Zasadniczo wygoda widoku może potencjalnie powodować niezamierzone problemy z wydajnością. Dzięki definicji widoku dostępnej w bazie danych dla każdego, ktoś będzie jej używał, nawet jeśli nie jest to najbardziej odpowiednie rozwiązanie.

Przynajmniej w przypadku widoku wbudowanego osoba pisząca instrukcję SQL jest bardziej świadoma rzeczywistego wykonywanego kodu SQL, a posiadanie całego tego kodu SQL daje możliwość poprawienia go pod kątem wydajności.

Moje dwa centy.

TAMING BEASTLY SQL

Uważam, że stosowanie regularnych reguł formatowania (które moje narzędzia robią automatycznie) może zamienić monstrualny SQL w coś, z czym mogę czytać i pracować.

SELECT row.col1
     , row.col2
     , person.*
  FROM some_table row
  LEFT
  JOIN ( SELECT 'person'  AS `person_type`
              , p.id      AS `id`
              , CONCAT(p.first_name,' ',p.surname) AS `name`
           FROM person p
          UNION ALL
         SELECT 'company' AS `person_type`
              , c.id      AS `id`
              , c.name    AS `name`
           FROM company c
       ) person
    ON person.id = row.person_id
   AND person.person_type = row.person_type

Równie prawdopodobne jest, że w ogóle unikałbym widoku wbudowanego i używałbym wyrażeń warunkowych z listy SELECT, chociaż staje się to bardziej nieporęczne w przypadku wielu kolumn.

SELECT row.col1
     , row.col2
     , row.person_type AS ref_person_type
     , row.person_id   AS ref_person_id
     , CASE
       WHEN row.person_type = 'person'  THEN p.id 
       WHEN row.person_type = 'company' THEN c.id
       END AS `person_id`
     , CASE
       WHEN row.person_type = 'person'  THEN CONCAT(p.first_name,' ',p.surname)
       WHEN row.person_type = 'company' THEN c.name
       END AS `name`
  FROM some_table row
  LEFT
  JOIN person p
    ON row.person_type = 'person'
   AND p.id = row.person_id
  LEFT
  JOIN company c
    ON row.person_type = 'company'
   AND c.id = row.person_id


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak korzystać z Coalesce w MySQL

  2. Grupuj według SQL z zamówieniem według

  3. Jak pominąć wiersz podczas importowania złego zrzutu MySQL

  4. Ustawianie wartości kolumn jako nazw kolumn w wyniku zapytania SQL

  5. Czy zapytanie PHP MYSQL może ignorować pustą zmienną w klauzuli WHERE?