Właśnie skonfigurowałem system rejestrowania, który składa się z wielu tabel o tym samym układzie.
Dla każdego źródła danych istnieje jedna tabela.
W przypadku przeglądarki dziennika chcę
- UNION wszystkie tabele dziennika ,
- filtruj je według konta ,
- dodaj pseudokolumnę do identyfikacji źródła,
- posortuj je według czasu ,
- i ogranicz je do stronicowania .
Wszystkie tabele zawierają pole o nazwie zeitpunkt
indeksowana kolumna daty / godziny.
Moja pierwsza próba to:
(SELECT l.id, l.account_id, l.vnum, l.count, l.preis, l.zeitpunkt AS zeit,
'hp' AS source FROM is_log AS l WHERE l.account_id = 730)
UNION
(SELECT l.id, l.account_id, l.vnum, l.count, l.preis, l.zeitpunkt,
'ig' AS source FROM ig_is_log AS l WHERE l.account_id = 730)
ORDER BY zeit DESC LIMIT 10;
Optymalizator nie może tutaj użyć indeksów, ponieważ wszystkie wiersze z obu tabel są zwracane przez podzapytania i sortowane po UNION
.
Moje obejście było następujące:
(SELECT l.id, l.account_id, l.vnum, l.count, l.preis, l.zeitpunkt AS zeit,
'hp' AS source FROM is_log AS l WHERE l.account_id = 730
ORDER BY l.zeitpunkt DESC LIMIT 10)
UNION
(SELECT l.id, l.account_id, l.vnum, l.count, l.preis, l.zeitpunkt,
'ig' AS source FROM ig_is_log AS l WHERE l.account_id = 730
ORDER BY l.zeitpunkt DESC LIMIT 10)
ORDER BY zeit DESC LIMIT 10;
Spodziewałem się, że silnik zapytań użyje tutaj indeksów, ponieważ oba podkwerendy powinny zostać posortowane i ograniczone już przed UNION
, który następnie łączy i sortuje wiersze.
Naprawdę myślałem, że to będzie to, ale uruchomienie EXPLAIN
zapytania powoduje, że podkwerendy wciąż przeszukują obie tabele.
EXPLAINing
same podkwerendy pokazują mi pożądaną optymalizację, ale UNIONing
razem ich nie robi.
Przegapiłem coś?
Wiem, że ORDER BY
klauzule w UNION
podzapytaniach są ignorowane bez znaku LIMIT
, ale jest pewien limit.
Edycja:
W rzeczywistości prawdopodobnie będą też zapytania bezaccount_id
warunku.
Tabele już istnieją i są wypełnione danymi. Mogą występować zmiany w układzie w zależności od źródła, dlatego chcę je podzielić. Ponadto klienci rejestrujący używają różnych poświadczeń z określonego powodu.
Muszę zachować rodzaj warstwy między czytnikami dzienników a rzeczywistymi tabelami.
Oto plany wykonania dla całego zapytania i pierwszego podzapytania, a także szczegółowo układ tabeli:
(account_id, zeitpunkt)
. Czy masz taki indeks? Drugi najlepszy byłby (myślę) singiel(zeitpunkt)
- ale wydajność, jeśli zostanie użyta, zależy od tego, jak częstoaccount_id=730
pojawiają się wiersze .UNION DISTINCT
? Nie ma potrzeby wymuszania sortowania i rozróżniania tam, ponieważ wyniki będą różne dla podkwerend, ze względu na dodatkową kolumnę identyfikacyjną. ZastosowanieUNION ALL
.source
kolumną? W ten sposób można uniknąćUNION
s i używać indeksów dla wszystkich danych.UNION ALL
inny system daje inny plan wykonania.Odpowiedzi:
Z ciekawości możesz wypróbować tę wersję? Optymalizator może oszukać te same indeksy, których użyłyby podzapytania osobno:
Nadal uważam, że najlepszym indeksem, jaki możesz mieć, jest związek
(account_id, zeitpunkt)
. Dałoby to szybko 10 rzędów i żadne sztuczki nie byłyby potrzebne.źródło
log entries / user
skaluje się liczba użytkowników i skala.account_id=?
, zachowaj oba.SELECT * FROM
MySQL w użyciu indeksów?(SELECT ...) AS a
, próbuje ona ocenić i zoptymalizować tabelę pochodną oddzielnie od innych tabel pochodnych, a następnie całe zapytanie.force index
da ci lepsze rozwiązanie.