Indeks global adalah indeks yang dibuat pada kolom non-kunci partisi dari tabel partisi dan dapat menerapkan kendala UNIK.
Applicability
Fitur ini didukung pada kluster PolarDB for PostgreSQL yang menjalankan PostgreSQL 14 dengan versi mesin minor 2.0.14.9.15.0 atau lebih baru.
Anda dapat melihat nomor versi mesin minor di console atau dengan menjalankan pernyataan SHOW polardb_version;. Jika versi mesin minor tidak memenuhi persyaratan, Anda dapat upgrade the minor engine version.
Informasi Latar Belakang
Seiring pertumbuhan data bisnis, partisi data menjadi fitur utama dalam database tingkat enterprise dan metode penting untuk mengurangi skala data. Tabel partisi dibagi menjadi beberapa tabel anak independen berdasarkan kunci partisi. Tabel-tabel anak tersebut dikelola secara terpisah guna meningkatkan kemudahan pengelolaan, kinerja keseluruhan, serta penyeimbangan beban.
Banyak pengguna PolarDB for PostgreSQL dan menggunakan tabel partisi untuk mengelola data mereka. Kasus penggunaan umum adalah mempartisi data berdasarkan waktu:
Gunakan waktu sebagai kunci partisi untuk tabel partisi.
Buat subpartisi baru secara berkala—misalnya mingguan atau bulanan—untuk menyimpan data baru.
Arsipkan subpartisi lama secara rutin untuk mengurangi biaya operasi dan maintenance (O&M) tabel partisi.
Dalam skenario tersebut, waktu biasanya digunakan sebagai kunci partisi, bukan sebagai primary key atau ID unik. Hal ini menimbulkan dua masalah:
Saat melakukan kueri data menggunakan kunci non-partisi, semua subpartisi harus dipindai karena sistem tidak dapat menentukan partisi mana yang berisi data tersebut.
Saat memodifikasi data menggunakan kunci non-partisi, keunikan data tidak dapat dijamin di seluruh tabel partisi.
Untuk mengatasi masalah ini, PolarDB for PostgreSQL dan menyediakan fitur indeks global. Berbeda dengan indeks lokal yang secara default dibuat pada setiap subpartisi, satu indeks global mencakup seluruh data tabel partisi—artinya satu indeks bersesuaian dengan beberapa subpartisi. Hal ini memungkinkan penerapan kendala unik secara global serta peningkatan signifikan pada kinerja kueri berdasarkan kunci non-partisi.
Batasan
Anda tetap dapat
ATTACHatauDETACHsubpartisi dari tabel partisi yang memiliki indeks global.Tentukan kata kunci
GLOBALdalam pernyataan `CREATE INDEX` untuk membuat indeks global. Jika kata kunci ini tidak ditentukan, indeks lokal akan dibuat secara default.Anda dapat membuat indeks global secara konkuren dengan menentukan kata kunci
CONCURRENTLY.Anda tidak dapat membuat indeks global pada tabel non-partisi atau pada tabel anak yang berisi subpartisi.
Indeks global tidak mendukung indeks ekspresi.
Anda tidak dapat membuat indeks global pada kolom kunci partisi dari tabel partisi.
Sintaks
Anda dapat membuat indeks global.
CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ [ IF NOT EXISTS ] name ] ON [ ONLY ] table_name [ USING method ]
( { column_name | ( expression ) } [ COLLATE collation ] [ opclass [ ( opclass_parameter = value [, ... ] ) ] ] [ ASC | DESC ] [ NULLS { FIRST | LAST } ] [, ...] )
[ INCLUDE ( column_name [, ...] ) ]
[ WITH ( storage_parameter [= value] [, ... ] ) ]
[ GLOBAL/LOCAL ]
[ TABLESPACE tablespace_name ]
[ WHERE predicate ]Contoh
Percepat query kunci non-partisi
Buat tabel partisi dengan kolom waktu sebagai kunci partisi.
CREATE TABLE partition_range ( id INT, a INT, b INT, created_date TIMESTAMP WITHOUT TIME ZONE ) PARTITION BY RANGE (created_date); CREATE TABLE partition_range_part01 PARTITION OF partition_range FOR VALUES FROM (MINVALUE) TO ('2020-01-01 00:00:00'); CREATE TABLE partition_range_part02 PARTITION OF partition_range FOR VALUES FROM ('2020-01-01 00:00:00') TO ('2020-02-01 00:00:00'); CREATE TABLE partition_range_part03 PARTITION OF partition_range FOR VALUES FROM ('2020-02-01 00:00:00') TO ('2020-03-01 00:00:00');Lakukan kueri pada tabel partisi berdasarkan kondisi kunci non-partisi.
EXPLAIN (COSTS OFF) SELECT * FROM partition_range WHERE id = 1;Hasilnya menunjukkan bahwa semua subpartisi dipindai. Fitur pemangkasan partisi tidak dapat digunakan.
QUERY PLAN ------------------------------------------------------------ Append -> Seq Scan on partition_range_part01 partition_range_1 Filter: (id = 1) -> Seq Scan on partition_range_part02 partition_range_2 Filter: (id = 1) -> Seq Scan on partition_range_part03 partition_range_3 Filter: (id = 1) (7 rows)Buat indeks lokal pada tabel partisi, lalu jalankan kueri lagi.
CREATE INDEX partition_range_idx_local ON partition_range(id); EXPLAIN (COSTS OFF) SELECT * FROM partition_range WHERE id = 1;Hasilnya menunjukkan bahwa indeks lokal dari semua subpartisi tetap dipindai karena indeks lokal dibuat pada setiap subpartisi.
QUERY PLAN -------------------------------------------------------------------------------------------------- Append -> Index Scan using partition_range_part01_id_idx on partition_range_part01 partition_range_1 Index Cond: (id = 1) -> Index Scan using partition_range_part02_id_idx on partition_range_part02 partition_range_2 Index Cond: (id = 1) -> Index Scan using partition_range_part03_id_idx on partition_range_part03 partition_range_3 Index Cond: (id = 1) (7 rows)Gunakan kata kunci
GLOBALuntuk membuat indeks global pada tabel partisi, lalu jalankan kueri lagi.CREATE INDEX partition_range_idx_global ON partition_range(id) GLOBAL; EXPLAIN (COSTS OFF) SELECT * FROM partition_range WHERE id = 1;Hasilnya menunjukkan bahwa database menggunakan indeks global untuk langsung menemukan subpartisi yang berisi data tersebut.
QUERY PLAN ----------------------------------------------------------------------- Global Index Scan using partition_range_idx_global on partition_range Index Cond: (id = 1) (2 rows)
Kendala unik untuk kunci non-partisi
Gunakan tabel partisi yang sama seperti pada contoh sebelumnya. Kunci partisinya adalah created_date, sedangkan kolom yang memerlukan kendala unik adalah id.
CREATE UNIQUE INDEX partition_range_id_unique_idx ON partition_range(id);
ERROR: unique constraint on partitioned table must include all partitioning columns
DETAIL: UNIQUE constraint on table "partition_range" lacks column "created_date" which is part of the partition key.Pada PostgreSQL native, upaya membuat kendala UNIK pada kunci non-partisi menggunakan indeks lokal akan menghasilkan error. Pesan error tersebut menunjukkan bahwa kunci partisi harus disertakan dalam indeks. PolarDB for PostgreSQL dan telah meningkatkan fitur indeks global. Secara default, kendala UNIK pada kunci non-partisi dikonversi menjadi kendala global berbasis indeks global. Perilaku ini dikontrol oleh parameter polar_pk_in_non_partition_column_mode dengan nilai default global_index. Jika nilai parameter diubah menjadi none, perilakunya akan sama seperti PostgreSQL native.
Namun, pembatasan ini tidak berlaku saat Anda menambahkan kendala UNIK ke indeks global, seperti yang ditunjukkan di bawah ini.
CREATE UNIQUE INDEX partition_range_id_unique_idx ON partition_range(id) GLOBAL;Uji Performa
Anda dapat menggunakan pgbench untuk menghasilkan data dengan faktor skala 80000 serta membuat tabel partisi dan tabel non-partisi.
Performa kueri titik pada kunci non-partisi
Kategori | TPS | |||||
Pernyataan Siap | Tidak digunakan | Digunakan | ||||
Konkurensi | 1 | 32 | 64 | 1 | 32 | 64 |
Standard table | 27.732 | 494.433 | 430.848 | 53.935 | 985.880 | 886.882 |
Partitioned table + local index | 367 | 4.155 | 3.688 | 856 | 8.742 | 6.790 |
Partitioned table + global index | 19.006 | 308.128 | 262.941 | 45.090 | 820.924 | 731.557 |
Performa TPC-B pada kunci non-partisi
Ini mencakup kueri titik dan pernyataan Data Manipulation Language (DML).
Kategori | TPS | |||||
Pernyataan Siap | Tidak digunakan | Digunakan | ||||
Konkurensi | 1 | 32 | 64 | 1 | 32 | 64 |
Standard table | 1.115 | 51.025 | 60.409 | 4.822 | 90.312 | 100.802 |
Partitioned table + local index | 271 | 2.903 | 2.524 | 550 | 5.276 | 4.237 |
Partitioned table + global index | Tidak didukung | 4.334 | 69.040 | 75.232 | ||
Kesimpulan
Indeks global dapat meningkatkan kinerja kueri titik dan pernyataan DML pada tabel partisi hingga satu orde besar.