Saya memiliki kueri yang relatif sederhana di atas meja dengan baris 1.5M:
SELECT mtid FROM publication
WHERE mtid IN (9762715) OR last_modifier=21321
LIMIT 5000;
EXPLAIN ANALYZE
keluaran:
Limit (cost=8.84..12.86 rows=1 width=8) (actual time=0.985..0.986 rows=1 loops=1) -> Bitmap Heap Scan on publication (cost=8.84..12.86 rows=1 width=8) (actual time=0.984..0.985 rows=1 loops=1) Recheck Cond: ((mtid = 9762715) OR (last_modifier = 21321)) -> BitmapOr (cost=8.84..8.84 rows=1 width=0) (actual time=0.971..0.971 rows=0 loops=1) -> Bitmap Index Scan on publication_pkey (cost=0.00..4.42 rows=1 width=0) (actual time=0.295..0.295 rows=1 loops=1) Index Cond: (mtid = 9762715) -> Bitmap Index Scan on publication_last_modifier_btree (cost=0.00..4.42 rows=1 width=0) (actual time=0.674..0.674 rows=0 loops=1) Index Cond: (last_modifier = 21321) Total runtime: 1.027 ms
Sejauh ini bagus, cepat dan menggunakan indeks yang tersedia.
Sekarang, jika saya memodifikasi sedikit kueri, hasilnya adalah:
SELECT mtid FROM publication
WHERE mtid IN (SELECT 9762715) OR last_modifier=21321
LIMIT 5000;
The EXPLAIN ANALYZE
output:
Limit (cost=0.01..2347.74 rows=5000 width=8) (actual time=2735.891..2841.398 rows=1 loops=1) -> Seq Scan on publication (cost=0.01..349652.84 rows=744661 width=8) (actual time=2735.888..2841.393 rows=1 loops=1) Filter: ((hashed SubPlan 1) OR (last_modifier = 21321)) SubPlan 1 -> Result (cost=0.00..0.01 rows=1 width=0) (actual time=0.001..0.001 rows=1 loops=1) Total runtime: 2841.442 ms
Tidak begitu cepat, dan menggunakan pemindaian seq ...
Tentu saja, kueri asli yang dijalankan oleh aplikasi sedikit lebih kompleks, dan bahkan lebih lambat, dan tentu saja orisinal yang dihasilkan hibernate tidak (SELECT 9762715)
, tetapi kelambatan ada bahkan untuk itu (SELECT 9762715)
! Permintaan dihasilkan oleh hibernate, sehingga cukup sulit untuk mengubahnya, dan beberapa fitur tidak tersedia (mis. UNION
Tidak tersedia, yang akan cepat).
Pertanyaan-pertanyaan
- Mengapa indeks tidak dapat digunakan dalam kasus kedua? Bagaimana mereka bisa digunakan?
- Bisakah saya meningkatkan kinerja permintaan dengan cara lain?
Pikiran tambahan
Tampaknya kita bisa menggunakan kasus pertama dengan melakukan SELECT secara manual, dan kemudian memasukkan daftar yang dihasilkan ke dalam kueri. Bahkan dengan 5000 angka dalam daftar IN () itu empat kali lebih cepat daripada solusi kedua. Namun, sepertinya SALAH (juga, bisa 100 kali lebih cepat :)). Ini benar-benar tidak dapat dimengerti mengapa perencana kueri menggunakan metode yang sama sekali berbeda untuk dua pertanyaan ini, jadi saya ingin mencari solusi yang lebih baik untuk masalah ini.
(SELECT 9762715)
.
(SELECT 9762715)
. Untuk pertanyaan hibernasi: itu bisa dilakukan, tetapi membutuhkan penulisan ulang kode serius, karena kami memiliki kueri kriteria hibernasi yang ditentukan pengguna yang diterjemahkan saat itu juga. Jadi pada dasarnya kami akan memodifikasi hibernate yang merupakan upaya besar dengan banyak efek samping yang mungkin.
JOIN
bukanIN ()
? Juga,publication
sudah dianalisis baru-baru ini?