Saya baru saja membuat sistem logging yang terdiri dari beberapa tabel dengan tata letak yang sama.
Ada satu tabel untuk setiap sumber data.
Untuk penampil log, saya mau
- UNION semua tabel log ,
- saring dengan akun ,
- tambahkan kolom semu untuk identifikasi sumber,
- urutkan berdasarkan waktu ,
- dan batasi untuk pagination .
Semua tabel berisi bidang yang disebut zeitpunkt
kolom tanggal / waktu yang diindeks.
Upaya pertama saya adalah:
(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;
Pengoptimal tidak dapat menggunakan indeks di sini karena semua baris dari kedua tabel dikembalikan oleh subqueries dan diurutkan setelah UNION
.
Solusi saya adalah sebagai berikut:
(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;
Saya mengharapkan mesin kueri akan menggunakan indeks di sini karena kedua subquery harus diurutkan dan dibatasi sebelumnya UNION
, yang kemudian menggabungkan dan mengurutkan baris.
Saya benar-benar berpikir ini akan menjadi itu, tetapi menjalankan EXPLAIN
kueri memberitahu saya subqueries masih mencari kedua tabel.
EXPLAINing
subqueries itu sendiri menunjukkan kepada saya optimasi yang diinginkan tetapi UNIONing
mereka bersama-sama tidak.
Apakah saya melewatkan sesuatu?
Saya tahu bahwa ORDER BY
klausa di dalam UNION
subqueries diabaikan tanpa LIMIT
, tetapi ada batasnya.
Sunting:
Sebenarnya, mungkin juga akan ada permintaan tanpaaccount_id
syarat.
Tabel sudah ada dan diisi dengan data. Mungkin ada perubahan dalam tata letak tergantung pada sumbernya sehingga saya ingin membuat mereka terbagi. Selain itu, klien logging menggunakan kredensial berbeda karena suatu alasan.
Saya harus menyimpan semacam layer antara pembaca log dan tabel aktual.
Berikut adalah rencana eksekusi untuk seluruh kueri dan subquery pertama serta tata letak tabel secara rinci:
(account_id, zeitpunkt)
. Apakah Anda memiliki indeks seperti itu? Yang terbaik adalah (saya pikir) single(zeitpunkt)
- tetapi efisiensi jika yang digunakan tergantung pada seberapa sering barisaccount_id=730
muncul.UNION DISTINCT
? Tidak perlu memaksakan pengurutan dan perbedaan di sana, karena hasilnya akan berbeda di seluruh subkueri, karena tambahan, kolom identifikasi. GunakanUNION ALL
.source
kolom? Dengan cara ini Anda dapat menghindariUNION
dan menggunakan indeks di semua data Anda.UNION ALL
menghasilkan rencana eksekusi yang berbeda.Jawaban:
Karena penasaran, dapatkah Anda mencoba versi ini? Mungkin menipu pengoptimal untuk menggunakan indeks yang sama yang akan digunakan subqueries secara terpisah:
Saya masih berpikir bahwa indeks terbaik yang bisa Anda miliki adalah senyawa
(account_id, zeitpunkt)
. Ini akan menghasilkan 10 baris dengan cepat, dan tidak ada trik yang diperlukan.sumber
log entries / user
skala kemauan.account_id=?
, pertahankan keduanya.SELECT * FROM
trik tiruan MySQL agar menggunakan indeks?(SELECT ...) AS a
, ia mencoba untuk mengevaluasi dan mengoptimalkan tabel turunan secara terpisah dari tabel turunan lainnya dan kemudian seluruh kueri.force index
akan memberi Anda solusi yang lebih baik.