Fitur Partial Result Cache (PTRC) di PolarDB for MySQL dapat digunakan untuk meningkatkan performa kueri dengan menyimpan cache set hasil antara dari operator dalam suatu kueri, sehingga mengurangi komputasi berulang pada operator yang kompleks. Topik ini menjelaskan konsep PTRC, prinsip kerjanya, pemilihan berbasis biaya, serta mekanisme umpan balik dinamisnya.
Konsep
PTRC adalah fitur yang menyimpan cache set hasil dari suatu operator dalam kueri. Misalnya, fitur ini dapat menyimpan hasil sementara dari operator seperti subkueri berkorelasi atau nested loop join. Jika operator yang sama dieksekusi lagi, sistem dapat menggunakan kembali hasil yang telah di-cache alih-alih mengeksekusinya ulang.
Kata "Partial" dalam PTRC memiliki dua makna:
-
PTRC menyimpan cache set hasil antara dari satu atau beberapa operator dalam kueri, bukan set hasil seluruh kueri.
-
Fitur ini tidak selalu menyimpan cache seluruh set hasil antara dari suatu operator. Karena batasan memori, mungkin hanya sebagian hasil yang di-cache.
Dibandingkan dengan cache kueri tradisional, PTRC bekerja pada granularitas yang lebih halus dengan mempercepat operator tertentu dalam kueri. Cache tersebut hanya ada selama durasi eksekusi kueri, sehingga penerapannya lebih luas. Karena optimasi dilakukan secara internal dalam satu kueri, masalah konsistensi data lintas node dapat dihindari. Operator apa pun dapat menggunakan PTRC jika menghasilkan output deterministik untuk sekumpulan parameter input tertentu. Pengoptimal memutuskan apakah akan menggunakan PTRC berdasarkan biaya.
Cara Kerja
Gagasan utama PTRC adalah menyimpan cache set hasil antara dari operator untuk menghindari eksekusi berulang. PTRC dapat mempercepat suatu operator jika memenuhi kondisi berikut:
-
Operator bergantung pada parameter berkorelasi selama eksekusinya dan dieksekusi beberapa kali. Contohnya termasuk operator nested loop join dan subkueri berkorelasi.
-
Untuk parameter berkorelasi yang sama, hasil operator selalu identik. Misalnya, operator tidak boleh mengandung fungsi non-deterministik seperti
RANDOM(),NOW(), atau user-defined functions (UDFs). Penggunaan fungsi tersebut akan mengompromikan kebenaran hasil akhir.
Parameter berkorelasi adalah parameter eksternal yang menjadi acuan operator selama eksekusinya. Sebagai contoh, dalam operasi join t1 join t2 on t1.a = t2.a, jika tabel t1 merupakan driving table, setiap baris dari tabel t1 di-join dengan tabel t2. Dalam kasus ini, t1.a dianggap sebagai parameter berkorelasi untuk operator nested loop join. Jika kolom t1.a dalam tabel t1 berisi banyak nilai duplikat, PTRC dapat mengurangi komputasi berulang. Contoh lain adalah subkueri berkorelasi, di mana setiap eksekusi subkueri bergantung pada nilai dari query luar.
Kueri TPC-H Q17 menggambarkan cara kerja PTRC. Kueri tersebut adalah sebagai berikut:
SELECT
sum(l_extendedprice) / 7.0 AS avg_yearly
FROM
lineitem,
part
WHERE
p_partkey = l_partkey
AND p_brand = 'Brand#34'
AND p_container = 'MED BOX'
AND l_quantity < (
SELECT
0.2 * avg(l_quantity)
FROM
lineitem
WHERE
l_partkey = p_partkey
);
PTRC menggunakan parameter berkorelasi operator sebagai kunci dan hasil eksekusi sebagai nilai. Untuk TPC-H Q17, format cache PTRC adalah: key = p_partkey, value = [true/false].
Gambar berikut menunjukkan alur eksekusi utama PTRC untuk subkueri berkorelasi dalam TPC-H Q17:
Setiap kali subkueri berkorelasi dievaluasi, sistem mencari hasilnya dalam cache PTRC menggunakan nilai p_partkey:
-
Jika hasil tidak ditemukan (cache miss), sistem mengeksekusi subkueri dan menyimpan hasilnya dalam cache PTRC.
-
Jika hasil ditemukan (cache hit), sistem langsung mengembalikan nilai yang di-cache, sehingga menghindari eksekusi subkueri berulang.
Dalam TPC-H Q17, subkueri dijalankan setelah tabel part dan tabel lineitem di-join. Hasil join tersebut berisi banyak nilai duplikat untuk p_partkey, yang merupakan parameter berkorelasi untuk subkueri. Akibatnya, PTRC mencapai tingkat hit cache yang sangat tinggi, sehingga memberikan peningkatan performa signifikan.
Anda dapat menggunakan perintah EXPLAIN untuk melihat rencana eksekusi. Adanya operator Partial Result Cache dalam rencana eksekusi sebelum subkueri menunjukkan bahwa PTRC digunakan. Sebagai contoh, dalam output EXPLAIN untuk TPC-H Q17, Partial result cache: keys(part.P_PARTKEY) merupakan node cache PTRC.
*************************** 1. row ***************************
EXPLAIN: -> Aggregate: sum(lineitem.L_EXTENDEDPRICE)
-> Nested loop inner join (cost=743267.04 rows=509876)
-> Filter: ((part.P_CONTAINER = 'MED BOX') and (part.P_BRAND = 'Brand#34')) (cost=204145.06 rows=19096)
-> Table scan on part (cost=204145.06 rows=1909557)
-> Filter: (lineitem.L_QUANTITY < (select #2)) (cost=25.56 rows=27)
-> Index lookup on lineitem using LINEITEM_FK2 (L_PARTKEY=part.P_PARTKEY) (cost=25.56 rows=27)
-> Select #2 (subquery in condition; dependent)
-> Partial result cache: keys(part.P_PARTKEY)
-> Aggregate: avg(lineitem.L_QUANTITY)
-> Index lookup on lineitem using LINEITEM_FK2 (L_PARTKEY=part.P_PARTKEY) (cost=28.23 rows=27)
Prasyarat
Kluster PolarDB for MySQL Anda harus menggunakan versi 8.0 dengan revisi 8.0.2.2.9 atau lebih baru. Anda dapat memeriksa versi kluster Anda dengan mengikuti petunjuk dalam Query engine versions.
Parameter
|
Parameter |
Level |
Deskripsi |
|
partial_result_cache_enabled |
Global/Session |
Mengaktifkan atau menonaktifkan fitur Partial Result Cache (PTRC). Nilai yang valid:
|
|
partial_result_cache_cost_threshold |
Global/Session |
Ambang batas biaya untuk PTRC. Pengoptimal hanya mempertimbangkan penggunaan PTRC jika total biaya kueri melebihi ambang batas ini. Rentang nilai: 0 hingga 18446744073709551615. Nilai default: 10000. |
|
partial_result_cache_check_frequency |
Global/Session |
Frekuensi pemicuan mekanisme umpan balik dinamis. Pemeriksaan dilakukan ketika jumlah kumulatif cache miss mencapai nilai ini. Rentang nilai: 0 hingga 18446744073709551615. Nilai default: 200. |
|
partial_result_cache_low_hit_rate |
Global/Session |
Ambang batas watermark rendah untuk tingkat hit cache. Pengoptimal hanya mempertimbangkan penggunaan PTRC jika perkiraan tingkat hit berada di atas nilai ini. Jika PTRC sudah digunakan, mekanisme umpan balik dinamis akan menonaktifkannya jika tingkat hit aktual turun di bawah ambang batas ini. Rentang nilai: 0 hingga 100. Nilai default: 20. |
|
partial_result_cache_high_hit_rate |
Global/Session |
Ambang batas watermark tinggi untuk tingkat hit cache. Ketika penggunaan memori mencapai batasnya dan tingkat hit berada di atas nilai ini, sistem memindahkan cache dari memori ke penyimpanan disk. Data cache yang sudah ada juga dipindahkan ke disk. Rentang nilai: 0 hingga 100. Nilai default: 70. |
|
partial_result_cache_max_mem_size |
Global/Session |
Jumlah kumulatif memori yang dapat digunakan PTRC untuk satu kueri. Jika kueri berisi beberapa operator yang menggunakan PTRC, total penggunaan memorinya tidak boleh melebihi batas ini. Rentang nilai: 0 hingga 18446744073709551615. Satuan: Byte. Nilai default: 67108864. |
Pemilihan Berbasis Biaya
Seperti yang ditunjukkan oleh alur eksekusi PTRC, mengaktifkan PTRC tidak selalu menguntungkan. Efektivitasnya bergantung pada tingkat hit cache. Jika tingkat hit rendah, PTRC justru dapat menambah overhead performa akibat operasi seperti pemeriksaan cache dan peningkatan konsumsi memori.
Untuk menghindari overhead yang tidak perlu, pengoptimal menggunakan pendekatan berbasis biaya dalam memutuskan penggunaan PTRC. Pendekatan ini mengevaluasi dua faktor utama:
-
Pengoptimal hanya mempertimbangkan penggunaan PTRC jika total biaya kueri melebihi nilai
partial_result_cache_cost_threshold. -
Perkiraan tingkat hit cache untuk operator harus lebih tinggi daripada nilai
partial_result_cache_low_hit_rate.
Saat membuat keputusan berbasis biaya, pengoptimal pertama-tama memeriksa parameter partial_result_cache_cost_threshold.
-
Jika total biaya kueri berada di bawah ambang batas ini, pengoptimal menganggap kueri tersebut berbiaya rendah dan kemungkinan besar akan dieksekusi dengan cepat. Keuntungan performa dari PTRC akan minimal, sedangkan overhead dari pemeriksaan cache dapat meningkatkan latensi untuk kueri singkat dengan konkurensi tinggi. Oleh karena itu, pengoptimal menggunakan ambang batas biaya global ini untuk sepenuhnya melewati PTRC pada kueri murah. Hal ini juga menghemat overhead evaluasi semua ekspresi untuk kelayakan PTRC.
-
Jika total biaya kueri lebih besar atau sama dengan
partial_result_cache_cost_threshold, pengoptimal mengevaluasi semua operator yang memenuhi syarat untuk PTRC dan memperkirakan tingkat hit cachenya menggunakan rumus berikut:hit_rate = (fanout - ndv) / fanoutDalam rumus ini,
fanoutadalah jumlah total eksekusi yang diharapkan untuk suatu operator, danndvadalah jumlah nilai unik untuk kunci PTRC, yaitu kombinasi semua parameter berkorelasi.
Jika perkiraan hit_rate lebih rendah daripada nilai partial_result_cache_low_hit_rate, pengoptimal tidak menggunakan PTRC untuk operator tersebut. Namun, dalam model biaya MySQL yang ada, statistik bergantung pada data indeks tabel atau histogram. Jika kolom parameter berkorelasi tidak memiliki indeks atau histogram, pengoptimal tidak dapat memperkirakan ndv secara akurat. Dalam kasus seperti itu, pengoptimal mungkin secara proaktif mengaktifkan PTRC dan mengandalkan mekanisme umpan balik dinamis selama eksekusi untuk menentukan apakah akan terus menggunakannya.
Mekanisme Umpan Balik Dinamis
Selama fase eksekusi, setiap cache hit atau miss dicatat dalam statistik. Mekanisme umpan balik dinamis menggunakan informasi ini untuk menghitung tingkat hit cache aktual. Jika tingkat hit cache aktual turun di bawah nilai partial_result_cache_low_hit_rate, mekanisme ini segera menonaktifkan PTRC untuk sisa eksekusi. Hal ini mengembalikan kueri ke rencana eksekusi aslinya dan mengurangi overhead akibat cache yang tidak efisien.
Parameter partial_result_cache_check_frequency mengontrol seberapa sering pemeriksaan dinamis dilakukan. Parameter ini menentukan jumlah kumulatif cache miss yang memicu pemeriksaan. Sebagai contoh, dengan nilai default 200, mekanisme umpan balik dinamis dipicu setelah terjadi 200 cache miss.
Karena set hasil di-cache dalam memori, mekanisme umpan balik dinamis juga dipicu ketika penggunaan memori PTRC mencapai batasnya. Dalam skenario ini, mekanisme tidak hanya memeriksa apakah tingkat hit cache terlalu rendah, tetapi juga memutuskan apakah akan melakukan eviction data atau memindahkan set hasil ke disk.
Saat penggunaan memori PTRC mencapai batasnya, kebijakan umpan balik berikut diterapkan:
-
Jika
hit_rateberada di bawah nilaipartial_result_cache_low_hit_rate, sistem menganggap tingkat hit terlalu rendah dan menonaktifkan PTRC. -
Jika
hit_rateberada di atas nilaipartial_result_cache_high_hit_rate, sistem memindahkan data cache dari memori ke penyimpanan disk. Peningkatan performa yang dapat diprediksi masih diharapkan meskipun menggunakan caching berbasis disk. -
Jika
hit_rateberada di antara ambang batas watermark rendah dan tinggi, sistem menerapkan kebijakan penggantian data least recently used (LRU). Data yang paling jarang digunakan dihapus dari cache untuk memberi ruang bagi data baru. Jika batas memori tercapai lagi setelah data baru di-cache, proses ini diulang mulai dari langkah 1.
Parameter partial_result_cache_max_mem_size membatasi total penggunaan memori untuk PTRC dalam satu kueri. Jika total memori yang digunakan oleh semua instans PTRC dalam kueri melebihi batas ini, sistem memicu mekanisme umpan balik dinamis untuk semuanya.
Tes Performa
Seperti yang dibahas dalam bagian pemilihan berbasis biaya, faktor utama yang memengaruhi manfaat performa PTRC adalah:
-
Biaya eksekusi operator yang dipercepat harus cukup tinggi. Jika operator itu sendiri murah untuk dijalankan, potensi peningkatan performa dari caching menjadi terbatas.
-
Tingkat hit cache harus tinggi, karena tingkat yang lebih tinggi memberikan peningkatan performa yang lebih signifikan.
Ambil contoh tes TPC-H Q17:
SELECT sum(l_extendedprice) / 7.0 AS avg_yearly
FROM lineitem, part
WHERE p_partkey = l_partkey
AND p_brand = 'Brand#34'
AND p_container = 'MED BOX'
AND l_quantity < (
SELECT 0.2 * avg(l_quantity)
FROM lineitem
WHERE l_partkey = p_partkey
);
Subkueri dalam kueri ini dijalankan berkali-kali. Rencana eksekusi berikut menunjukkan bahwa PTRC sedang digunakan. Dalam pohon EXPLAIN untuk TPC-H Q17, node Partial result cache: keys(part.P_PARTKEY) menunjukkan bahwa PTRC diterapkan pada subkueri dependen:
EXPLAIN: -> Aggregate: sum(lineitem.L_EXTENDEDPRICE)
-> Nested loop inner join (cost=743267.04 rows=509876)
-> Filter: ((part.P_CONTAINER = 'MED BOX') and (part.P_BRAND = 'Brand#34')) (cost=204145.06 rows=19096)
-> Table scan on part (cost=204145.06 rows=1909557)
-> Filter: (lineitem.L_QUANTITY < (select #2)) (cost=25.56 rows=27)
-> Index lookup on lineitem using LINEITEM_FK2 (L_PARTKEY=part.P_PARTKEY) (cost=25.56 rows=27)
-> Select #2 (subquery in condition; dependent)
-> Partial result cache: keys(part.P_PARTKEY)
-> Aggregate: avg(lineitem.L_QUANTITY)
-> Index lookup on lineitem using LINEITEM_FK2 (L_PARTKEY=part.P_PARTKEY) (cost=28.23 rows=27)
Statistik pengujian menunjukkan bahwa mengaktifkan PTRC untuk subkueri dalam TPC-H Q17 mencapai tingkat hit cache hingga 96%, yang menghasilkan peningkatan performa signifikan. Gambar berikut menunjukkan data pengujian:
Ringkasan
PTRC menargetkan operator kompleks dalam satu kueri yang bergantung pada parameter berkorelasi. Dengan menyimpan cache set hasil antara dari operator-operator tersebut, PTRC mengurangi komputasi berulang. Anda dapat memperoleh peningkatan performa substansial jika tingkat hit cache cukup tinggi. Saat ini, PTRC dapat mempercepat berbagai operator, termasuk subkueri berkorelasi dan nested loop join (yang mencakup inner join, outer join, semi-join, dan anti-join).