Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.
Membangun untuk efisiensi dengan fungsi
Fungsi yang ditentukan pengguna bukan shard tunggal yang dioptimalkan secara default, tetapi mereka dapat dikonfigurasi untuk dijalankan sebagai operasi pecahan tunggal. Fungsi dapat merangkum logika dan memastikannya dijalankan dengan cara yang dioptimalkan dengan shard tunggal.
Mengapa operasi pecahan tunggal itu penting
Pemanfaatan sumber daya penting untuk kinerja dan efisiensi biaya. Operasi single-shard menggunakan sumber daya yang jauh lebih sedikit dibandingkan dengan operasi cross-shard. Misalnya, ketika menjalankan fungsi untuk menyisipkan satu juta baris, eksekusi shard tunggal menggunakan sekitar 90,5 ACUs dibandingkan dengan 126,5 ACUs untuk eksekusi cross-shard — peningkatan 35% dalam efisiensi sumber daya.
Eksekusi single-shard juga menyediakan:
-
Throughput 35% lebih tinggi dari operasi cross-shard
-
Waktu respons yang lebih dapat diprediksi
-
Skalabilitas yang lebih baik seiring pertumbuhan data
Operasi dan fungsi shard tunggal
Fungsi dijalankan pada pecahan ketika salah satu dari prasyarat ini terpenuhi:
-
Fungsi ini dibuat sebagai tidak dapat diubah dan disertakan dalam kueri yang dioptimalkan dengan pecahan tunggal
-
Fungsi didistribusikan oleh pengguna
Fungsi yang dijalankan pada pecahan bekerja dan menskalakan lebih baik karena mereka mengeksekusi di mana data berada.
Fungsi dan volatilitas
Untuk memeriksa volatilitas fungsi, gunakan kueri ini pada tabel sistem PostgreSQL:
SELECT DISTINCT nspname, proname, provolatile FROM pg_proc PRO JOIN pg_namespace NSP ON PRO.pronamespace = NSP.oid WHERE proname IN ('random', 'md5');
Contoh output:
nspname | proname | provolatile ------------+---------+------------- pg_catalog | md5 | i pg_catalog | random | v (2 rows)
Dalam contoh ini, md5() tidak dapat diubah dan tidak random() stabil. Ini berarti bahwa pernyataan yang dioptimalkan dengan pecahan tunggal yang menyertakan md5() tetap dioptimalkan pecahan tunggal, sedangkan pernyataan yang menyertakan tidak. random()
Contoh dengan fungsi yang tidak dapat diubah:
EXPLAIN ANALYZE SELECT pg_catalog.md5('123') FROM s1.t1 WHERE col_a = 776586194 AND col_b = 654849524 AND col_c = '3ac2f2affb02987159ccd6ebd23e1ae5';
QUERY PLAN
----------------------------------------------------
Foreign Scan (cost=100.00..101.00 rows=100 width=0)
(actual time=3.409..3.409 rows=1 loops=1)
Single Shard Optimized
Planning Time: 0.313 ms
Execution Time: 4.253 ms
(4 rows)
Contoh dengan fungsi volatile:
EXPLAIN ANALYZE SELECT pg_catalog.random() FROM s1.t1 WHERE col_a = 776586194 AND col_b = 654849524 AND col_c = '3ac2f2affb02987159ccd6ebd23e1ae5';
QUERY PLAN ------------------------------------------------------ Foreign Scan on t1_fs00001 t1 (cost=100.00..15905.15 rows=1 width=8) (actual time=0.658..0.658 rows=1 loops=1) Planning Time: 0.263 ms Execution Time: 2.892 ms (3 rows)
Output menunjukkan bahwa md5() didorong ke bawah dan dieksekusi sebagai shard tunggal yang dioptimalkan, sementara random() tidak.
Mendistribusikan fungsi
Fungsi yang mengakses data hanya pada satu pecahan harus dijalankan pada pecahan itu untuk mendapatkan manfaat kinerja. Fungsi harus didistribusikan, dan tanda tangan fungsi harus menyertakan tombol shard lengkap—semua kolom dalam kunci shard harus diteruskan sebagai parameter ke fungsi.
Contoh fungsi:
CREATE OR REPLACE FUNCTION s1.func1( param_a bigint, param_b bigint, param_c char(100) ) RETURNS int AS $$ DECLARE res int; BEGIN SELECT COUNT(*) INTO res FROM s1.t1 WHERE s1.t1.col_a = param_a AND s1.t1.col_b = param_b AND s1.t1.col_c = param_c; RETURN res; END $$ LANGUAGE plpgsql;
Sebelum distribusi, fungsinya tidak dioptimalkan dengan pecahan tunggal:
EXPLAIN ANALYZE SELECT * FROM s1.func1(776586194, 654849524, '3ac2f2affb02987159ccd6ebd23e1ae5');
QUERY PLAN
------------------------------------------------------------------------------------------------------
Function Scan on func1 (cost=0.25..0.26 rows=1 width=4)
(actual time=37.503..37.503 rows=1 loops=1)
Planning Time: 0.901 ms
Execution Time: 51.647 ms
(3 rows)
Untuk mendistribusikan fungsi:
SELECT rds_aurora.limitless_distribute_function( 's1.func1(bigint,bigint,character)', ARRAY['param_a','param_b','param_c'], 's1.t1' );
Setelah distribusi, fungsinya dioptimalkan dengan pecahan tunggal:
EXPLAIN ANALYZE SELECT * FROM s1.func1(776586194, 654849524, '3ac2f2affb02987159ccd6ebd23e1ae5');
QUERY PLAN
------------------------------------------------------------------------------------------------
Foreign Scan (cost=100.00..101.00 rows=100 width=0)
(actual time=4.332..4.333 rows=1 loops=1)
Single Shard Optimized
Planning Time: 0.857 ms
Execution Time: 5.116 ms
(4 rows)
Anda dapat mengonfirmasi optimasi shard tunggal dengan memeriksa sso_calls kolom di: rds_aurora.limitless_stat_statements
subcluster_id | subcluster_type | calls | sso_calls | query --------------+-----------------+-------+-----------+-------------------------------------- 2 | router | 2 | 1 | SELECT * FROM s1.func1( $1, $2, $3 ) 3 | router | 1 | 1 | SELECT * FROM s1.func1( $1, $2, $3 ) (2 rows)
Fungsi dan pola efisiensi
Mengeksekusi logika dekat dengan data lebih efisien, dan fungsi memainkan peran kunci dalam mencapai hal ini. Ada dua kasus penggunaan utama untuk meningkatkan efisiensi dengan fungsi:
-
Mengekstrak kunci pecahan dari data kompleks untuk menjalankan fungsi terpisah yang dioptimalkan dengan pecahan tunggal
-
Mengubah beban kerja cross-shard menjadi shard tunggal yang dioptimalkan dengan memisahkan logika cross-shard dari pernyataan yang dioptimalkan dengan pecahan tunggal
Mengekstrak kunci pecahan dari data kompleks
Pertimbangkan fungsi dengan tanda tangan s3.func3(p_json_doc json) yang melakukan beberapa operasi database. Operasi ini akan dijalankan di semua pecahan dalam transaksi yang mencakup semua pecahan. Jika dokumen JSON berisi kunci shard, Anda dapat membangun fungsi single-shard yang dioptimalkan untuk melakukan operasi database.
Pola asli:
s3.func3(p_json_doc json) database operation 1; database operation 2; database operation 3;
Pola yang dioptimalkan:
s3.func3(p_json_doc json) DECLARE v_a bigint; BEGIN v_a := (p_json_doc->>'field_a')::bigint; SELECT s3.func3_INNER(v_a, p_json_doc); END;
Dimana fungsi batin melakukan:
s3.func3_INNER(p_a, p_json_doc) database operation 1 WHERE shard_key = p_a; database operation 2 WHERE shard_key = p_a; database operation 3 WHERE shard_key = p_a;
Dalam pola ini, kunci pecahan dienkapsulasi dalam tipe data yang kompleks atau dapat dideduksi dari parameter lain. Logika, akses data, dan fungsi dapat menentukan, mengekstrak, atau membangun kunci shard, kemudian memanggil fungsi yang dioptimalkan shard tunggal yang melakukan operasi hanya dengan satu pecahan. Karena antarmuka aplikasi tidak berubah, pengoptimalan relatif mudah untuk diuji.
Menunda kunci shard dari fungsi atau data lain
Pola desain lain berlaku ketika logika atau akses data menghitung atau menentukan kunci shard. Ini berguna ketika sebuah fungsi dapat dieksekusi pada satu pecahan untuk sebagian besar pemanggilan, tetapi kadang-kadang membutuhkan eksekusi cross-shard.
Pola asli:
NEWORD(INTEGER, …) RETURNS NUMERIC DECLARE all_whid_local := true; LOOP through the order lines Generate warehouse ID; IF generated warehouse ID == input warehouse ID THEN ol_supply_whid := input warehouse ID; ELSE all_whid_local := false; ol_supply_whid := generated warehouse ID; END IF; … END LOOP; … RETURN no_s_quantity;
Pola yang dioptimalkan dengan fungsi terpisah:
CREATE OR REPLACE FUNCTION NEWORD_sso(no_w_id INTEGER, …) RETURNS NUMERIC … RETURN no_s_quantity; … END; LANGUAGE 'plpgsql'; SELECT rds_aurora.limitless_distribute_function( 'NEWORD_sso(int,…)', ARRAY['no_w_id'], 'warehouse' ); CREATE OR REPLACE FUNCTION NEWORD_crosshard(no_w_id INTEGER, …) RETURNS NUMERIC … RETURN no_s_quantity; … END; LANGUAGE 'plpgsql';
Kemudian minta fungsi utama memanggil versi single-shard yang dioptimalkan atau cross-shard:
IF all_whid_local THEN SELECT NEWORD_sso(…) INTO no_s_quantity; ELSE SELECT NEWORD_crosshard(…) INTO no_s_quantity; END IF;
Pendekatan ini memungkinkan sebagian besar pemanggilan untuk mendapatkan keuntungan dari optimasi pecahan tunggal sambil mempertahankan perilaku yang benar untuk kasus yang memerlukan eksekusi cross-shard.
Memeriksa operasi pecahan tunggal
Gunakan EXPLAIN untuk memverifikasi apakah pernyataan dioptimalkan dengan pecahan tunggal. Output secara eksplisit melaporkan “Single Shard Optimized” untuk operasi yang dioptimalkan.
Pemanggilan cross-shard sebelum distribusi:
QUERY PLAN
---------------------------------------------------------------------
Function Scan on func1 (cost=0.25..0.26 rows=1 width=4)
(actual time=59.622..59.623 rows=1 loops=1)
Planning Time: 0.925 ms
Execution Time: 60.211 ms
Pemanggilan pecahan tunggal setelah distribusi:
QUERY PLAN
----------------------------------------------------------------------
Foreign Scan (cost=100.00..101.00 rows=100 width=0)
(actual time=4.576..4.577 rows=1 loops=1)
Single Shard Optimized
Planning Time: 1.483 ms
Execution Time: 5.404 ms
Perbedaan waktu eksekusi menunjukkan manfaat kinerja dari optimasi shard tunggal.