Anda dapat menggunakan ekstensi pg_hint_plan untuk menambahkan petunjuk ke pernyataan SQL, yang menentukan cara menjalankan pernyataan tersebut. Dengan demikian, Anda dapat mengoptimalkan rencana eksekusinya.
Informasi latar belakang
PostgreSQL menggunakan Optimalisasi berbasis biaya yang mengandalkan statistik data dibandingkan aturan statis. Optimizer mengevaluasi biaya dari semua rencana eksekusi yang mungkin untuk sebuah pernyataan SQL dan menjalankan rencana dengan biaya terendah. Meskipun optimizer berusaha semaksimal mungkin, rencana eksekusi yang dipilih mungkin bukan yang terbaik karena tidak mempertimbangkan hubungan mendasar antara data.
Anda dapat menentukan variabel Grand Unified Scheme (GUC) untuk menyesuaikan rencana eksekusi, tetapi ini akan memengaruhi seluruh sesi. Jika Anda ingin menghindari dampak pada seluruh sesi, gunakan pg_hint_plan untuk mengoptimalkan satu rencana eksekusi tunggal.
Peringatan
- Data Management (DMS) tidak mendukung petunjuk. Anda harus menggunakan metode lain untuk mengakses database.
- pg_hint_plan hanya membaca petunjuk dari blok komentar pertama.
- pg_hint_plan hanya menerima huruf, angka, spasi, dan karakter khusus berikut: _ , ( ). Karakter lainnya akan langsung menghentikan proses penguraian.
- pg_hint_plan membandingkan nama objek secara sensitif terhadap huruf besar/kecil, berbeda dengan PostgreSQL yang tidak sensitif terhadap huruf besar/kecil. Sebagai contoh, objek bernama TBL dalam petunjuk hanya cocok dengan TBL di database. Objek bernama tbl atau Tbl akan diabaikan.
Batasan
- Petunjuk hanya berlaku untuk jenis pernyataan berikut:
- Pernyataan SELECT, INSERT, UPDATE, dan DELETE.
- Pernyataan RETURN QUERY.
- Pernyataan EXECUTE QUERY.
- Pernyataan OPEN.
- Pernyataan FOR.
- Petunjuk harus ditempatkan langsung setelah kata pertama dari pernyataan SQL. Jika petunjuk ditempatkan sebelum kata pertama, maka tidak akan dianggap sebagai bagian dari query.
Membuat dan memuat ekstensi pg_hint_plan
- Buat ekstensi.
CREATE EXTENSION pg_hint_plan; - Muat ekstensi.
- Muat ekstensi secara otomatis untuk satu pengguna.
- Jalankan pernyataan berikut untuk memuat ekstensi.
ALTER USER xxx set session_preload_libraries='pg_hint_plan';Catatan Ganti xxx dalam pernyataan tersebut dengan nama pengguna aktual. - Jalankan pernyataan berikut untuk memuat ekstensi untuk satu database.
ALTER DATABASE xxx set session_preload_libraries='pg_hint_plan';
Catatan Jika akun tidak dapat masuk ke database karena konfigurasi yang tidak tepat, jalankan salah satu pernyataan berikut untuk masuk ke PolarDB melalui akun atau database lain dan reset konfigurasinya.ALTER USER xxx reset session_preload_libraries; ALTER DATABASE xxx reset session_preload_libraries; - Jalankan pernyataan berikut untuk memuat ekstensi.
- Muat ekstensi secara otomatis untuk kluster database.
Untuk menggunakan ekstensi pg_hint_plan, kunjungi Quota Center. Klik Apply di kolom Actions yang sesuai dengan polardb_pg_pg_hint_plan.
- Periksa apakah ekstensi telah dimuat.
- Jalankan pernyataan berikut untuk mengizinkan informasi debug dikirim ke klien.
SET pg_hint_plan.debug_print TO on; SET pg_hint_plan.message_level TO notice; - Jalankan pernyataan berikut untuk memeriksa apakah ekstensi telah dimuat.
Jika ekstensi telah dimuat, informasi berikut akan dikembalikan./*+Set(enable_seqscan 1)*/select 1;NOTICE: pg_hint_plan: used hint: Set(enable_seqscan 1) - Jalankan pernyataan berikut untuk menghentikan pengiriman informasi debug ke klien.
RESET pg_hint_plan.debug_print; RESET pg_hint_plan.message_level;
- Jalankan pernyataan berikut untuk mengizinkan informasi debug dikirim ke klien.
- Muat ekstensi secara otomatis untuk satu pengguna.
Catatan penggunaan
- Basic usage
Petunjuk dimulai dengan kombinasi garis miring maju, tanda bintang, dan tanda tambah (
/*+) serta diakhiri dengan kombinasi tanda bintang dan garis miring maju (*/). Petunjuk terdiri dari nama petunjuk dan parameter. Parameter diapit oleh sepasang tanda kurung () dan dipisahkan oleh spasi. Untuk meningkatkan keterbacaan, Anda dapat memulai setiap petunjuk pada baris baru.Contoh:
Dalam contoh ini, HashJoin digunakan sebagai metode penggabungan, dan tabel pgbench_accounts dipindai menggunakan metode SeqScan.
Hasil berikut dikembalikan:/*+ HashJoin(a b) SeqScan(a) */ EXPLAIN SELECT * FROM pgbench_branches b JOIN pgbench_accounts a ON b.bid = a.bid ORDER BY a.aid;QUERY PLAN --------------------------------------------------------------------------------------- Sort (cost=31465.84..31715.84 rows=100000 width=197) Sort Key: a.aid -> Hash Join (cost=1.02..4016.02 rows=100000 width=197) Hash Cond: (a.bid = b.bid) -> Seq Scan on pgbench_accounts a (cost=0.00..2640.00 rows=100000 width=97) -> Hash (cost=1.01..1.01 rows=1 width=100) -> Seq Scan on pgbench_branches b (cost=0.00..1.01 rows=1 width=100) (7 rows) - Hint tablePetunjuk dapat digunakan untuk mengoptimalkan rencana eksekusi pernyataan SQL. Namun, cara ini hanya nyaman jika pernyataan SQL dapat diedit. Jika pernyataan SQL tidak dapat diedit, Anda dapat menempatkan petunjuk dalam tabel bernama hint_plan.hints. Tabel tersebut terdiri dari kolom-kolom berikut.
Pernyataan berikut menunjukkan contoh tabel petunjuk. Secara default, pengguna yang membuat ekstensi pg_hint_plan memiliki izin pada tabel petunjuk. Ketika petunjuk ditambahkan ke komentar pernyataan dan tabel petunjuk, petunjuk dalam tabel petunjuk lebih diutamakan daripada petunjuk dalam komentar.Kolom Deskripsi id ID petunjuk. ID ini unik dan dibuat secara otomatis. norm_query_string Pola yang cocok dengan pernyataan SQL tempat Anda ingin menambahkan petunjuk. Konstanta dalam pernyataan SQL harus diganti dengan tanda tanya (?) yang berfungsi sebagai wildcard. Karakter spasi adalah bagian penting dari pola. application_name Nama aplikasi tempat petunjuk diterapkan. Jika parameter ini dibiarkan kosong, petunjuk diterapkan ke semua aplikasi. hints Komentar yang berisi petunjuk. Anda tidak perlu menyertakan tanda komentar. INSERT INTO hint_plan.hints(norm_query_string, application_name, hints) VALUES ( 'EXPLAIN (COSTS false) SELECT * FROM t1 WHERE t1.id = ?;', '', 'SeqScan(t1)' ); INSERT 0 1 UPDATE hint_plan.hints SET hints = 'IndexScan(t1)' WHERE id = 1; UPDATE 1 DELETE FROM hint_plan.hints WHERE id = 1; DELETE 1
Jenis petunjuk
- Hint types
Petunjuk dikategorikan menjadi enam jenis berdasarkan pengaruhnya terhadap rencana eksekusi:
- Hints for scan methods
Jenis petunjuk ini menentukan metode yang digunakan untuk memindai tabel tertentu. Jika tabel memiliki alias, ekstensi pg_hint_plan mengidentifikasi tabel berdasarkan alias tersebut. Metode pemindaian yang didukung mencakup SeqScan, IndexScan, dan lainnya.
Petunjuk untuk metode pemindaian efektif pada tabel biasa, tabel warisan, tabel tanpa log, tabel sementara, dan tabel sistem. Namun, petunjuk ini tidak berlaku untuk tabel eksternal, fungsi tabel, pernyataan dengan nilai konstan, ekspresi universal, tampilan, serta subquery.
Contoh:/*+ SeqScan(t1) IndexScan(t2 t2_pkey) */ SELECT * FROM table1 t1 JOIN table table2 t2 ON (t1.key = t2.key); - Hints for join methods
Jenis petunjuk ini menentukan metode yang digunakan untuk menggabungkan tabel tertentu. Petunjuk untuk metode penggabungan efektif pada tabel biasa, tabel warisan, tabel tanpa log, tabel sementara, tabel eksternal, tabel sistem, fungsi tabel, pernyataan dengan nilai konstan, dan ekspresi universal. Namun, petunjuk ini tidak berlaku untuk tampilan dan subquery.
- Hints for join orderJenis petunjuk ini menentukan urutan penggabungan dua atau lebih tabel. Anda dapat menggunakan salah satu metode berikut untuk menentukan petunjuk urutan penggabungan:
- Tentukan urutan penggabungan tabel tanpa membatasi arah pada setiap tingkat penggabungan.
- Tentukan urutan penggabungan tabel beserta arah pada setiap tingkat penggabungan.
Contoh:/*+ NestLoop(t1 t2) MergeJoin(t1 t2 t3) Leading(t1 t2 t3) */ SELECT * FROM table1 t1 JOIN table table2 t2 ON (t1.key = t2.key) JOIN table table3 t3 ON (t2.key = t3.key);Catatan Komponen:- NestLoop(t1 t2): menentukan metode penggabungan tabel t1 dan t2.
- MergeJoin(t1 t2 t3): menentukan metode penggabungan tabel t1, t2, dan t3.
- Leading(t1 t2 t3): menentukan urutan penggabungan ketiga tabel.
- Hints for row number correction
Jenis petunjuk ini mengoreksi kesalahan jumlah baris yang disebabkan oleh pembatasan optimizer.
/*+ Rows(a b #10) */ SELECT... ; # Mengatur jumlah baris hasil penggabungan menjadi 10. /*+ Rows(a b +10) */ SELECT... ; # Meningkatkan jumlah baris sebesar 10. /*+ Rows(a b -10) */ SELECT... ; # Mengurangi jumlah baris sebesar 10. /*+ Rows(a b *10) */ SELECT... ; # Meningkatkan jumlah baris sebesar 10 kali. - Hints for parallel execution
Jenis petunjuk ini menentukan rencana yang digunakan untuk mengeksekusi pernyataan SQL secara paralel.
Petunjuk untuk eksekusi paralel efektif pada tabel biasa, tabel warisan, tabel tanpa log, dan tabel sistem. Namun, petunjuk ini tidak berlaku untuk tabel eksternal, klausa dengan nilai konstan, ekspresi universal, tampilan, dan subquery. Anda dapat menentukan tabel internal dari tampilan menggunakan nama asli atau alias mereka.
Contoh berikut menunjukkan cara pernyataan SQL dieksekusi secara berbeda pada setiap tabel:- Contoh 1: Atur derajat paralelisme (DOP) untuk tabel c1 menjadi 3, dan untuk tabel c2 menjadi 5.
Hasil berikut dikembalikan:EXPLAIN /*+ Parallel(c1 3 hard) Parallel(c2 5 hard) */ SELECT c2.a FROM c1 JOIN c2 ON (c1.a = c2.a);QUERY PLAN ------------------------------------------------------------------------------- Hash Join (cost=2.86..11406.38 rows=101 width=4) Hash Cond: (c1.a = c2.a) -> Gather (cost=0.00..7652.13 rows=1000101 width=4) Workers Planned: 3 -> Parallel Seq Scan on c1 (cost=0.00..7652.13 rows=322613 width=4) -> Hash (cost=1.59..1.59 rows=101 width=4) -> Gather (cost=0.00..1.59 rows=101 width=4) Workers Planned: 5 -> Parallel Seq Scan on c2 (cost=0.00..1.59 rows=59 width=4) - Contoh 2: Atur DOP untuk tabel t1 menjadi 5.
Hasil berikut dikembalikan:EXPLAIN /*+ Parallel(tl 5 hard) */ SELECT sum(a) FROM tl;QUERY PLAN ----------------------------------------------------------------------------------- Finalize Aggregate (cost=693.02..693.03 rows=1 width=8) -> Gather (cost=693.00..693.01 rows=5 width=8) Workers Planned: 5 -> Partial Aggregate (cost=693.00..693.01 rows=1 width=8) -> Parallel Seq Scan on tl (cost=0.00..643.00 rows=20000 width=4)
- Contoh 1: Atur derajat paralelisme (DOP) untuk tabel c1 menjadi 3, dan untuk tabel c2 menjadi 5.
- Hints for GUC parameter setting
Jenis petunjuk ini sementara mengubah nilai parameter GUC. Nilai parameter GUC hanya berlaku saat executor menghasilkan rencana eksekusi. Nilai-nilai ini membantu meningkatkan kinerja query tanpa memengaruhi seluruh sesi. Jika lebih dari satu petunjuk diatur untuk parameter GUC, petunjuk terbaru yang diterapkan.
Contoh:/*+ Set(random_page_cost 2.0) */ SELECT * FROM table1 t1 WHERE key = 'value';
- Hints for scan methods
- List of hint syntaxes
Jenis Sintaksis petunjuk Deskripsi Petunjuk untuk metode pemindaian SeqScan(table) Menentukan pemindaian urutan. TidScan(table) Menentukan pemindaian TID. IndexScan(table[ index...]) Menentukan pemindaian indeks. Anda dapat menentukan indeks. IndexOnlyScan(table[ index...]) Menentukan pemindaian indeks saja. Anda dapat menentukan indeks. BitmapScan(table[ index...]) Menentukan pemindaian bitmap. Anda dapat menentukan indeks. NoSeqScan(table) Melarang pemindaian urutan. NoTidScan(table) Melarang pemindaian TID. NoIndexScan(table) Melarang pemindaian indeks. NoIndexOnlyScan(table) Melarang pemindaian indeks. Hanya tabel yang dipindai. NoBitmapScan(table) Melarang pemindaian bitmap. Petunjuk untuk metode penggabungan NestLoop(table table[ table...]) Menentukan penggabungan loop bersarang. HashJoin(table table[ table...]) Menentukan penggabungan hash. MergeJoin(table table[ table...]) Menentukan penggabungan merge. NoNestLoop(table table[ table...]) Melarang penggabungan loop bersarang. NoHashJoin(table table[ table...]) Melarang penggabungan hash. NoMergeJoin(table table[ table...]) Melarang penggabungan merge. Petunjuk untuk urutan penggabungan Leading(table table[ table...]) Menentukan urutan penggabungan. Leading(<join pair>) Menentukan urutan dan arah penggabungan. Petunjuk untuk koreksi jumlah baris Rows(table table[ table...] correction) Mengoreksi jumlah baris hasil penggabungan yang diperoleh dari tabel yang ditentukan. Operator berikut didukung: #<n>, + <n>, -<n>, dan * <n>. Operator <n> didukung oleh fungsi strtod. Petunjuk untuk eksekusi paralel Parallel(table <# of workers> [soft|hard]) Menentukan atau melarang eksekusi paralel tabel yang ditentukan. Catatan- Parameter <worker#> menentukan jumlah program kerja yang diperlukan. Nilai 0 menentukan untuk melarang eksekusi paralel.
- Jika parameter ketiga diatur ke soft, hanya nilai parameter max_parallel_workers_per_gather yang diubah dan parameter lainnya ditentukan oleh optimizer.
- Jika parameter ketiga diatur ke hard, nilai semua parameter terkait diubah. Parameter ketiga diatur ke soft secara default.
PX(<# of workers>) Menentukan eksekusi paralel lintas node. Catatan <# of workers> menentukan DOP.NoPX() Melarang eksekusi paralel lintas node. Petunjuk untuk pengaturan parameter GUC Set(GUC-param value) Menentukan nilai parameter GUC saat optimizer berjalan. Catatan pg_hint_plan juga dapat menentukan rencana eksekusi yang dihasilkan selama eksekusi paralel lintas node. Selama eksekusi paralel lintas node, petunjuk Rows(table table[ table...] correction) tidak didukung. Petunjuk untuk metode penggabungan hanya berlaku untuk menggabungkan dua tabel, sedangkan petunjuk untuk urutan penggabungan hanya dapat digunakan untuk semua tabel.