PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Perbaikan Partisi di PostgreSQL 11

Sistem partisi di PostgreSQL pertama kali ditambahkan di PostgreSQL 8.1 oleh pendiri 2ndQuadrant Simon Riggs . Itu didasarkan pada pewarisan relasi dan menggunakan teknik baru untuk mengecualikan tabel agar tidak dipindai oleh kueri, yang disebut "pengecualian kendala". Meskipun merupakan langkah maju yang besar pada saat itu, saat ini dianggap rumit untuk digunakan serta lambat, dan karenanya perlu diganti.

Dalam versi 10, itu digantikan berkat upaya heroik oleh Amit Langote dengan "partisi deklaratif" bergaya modern. Teknologi baru ini berarti Anda tidak perlu lagi menulis kode secara manual untuk merutekan tupel ke partisi yang benar, dan tidak lagi perlu mendeklarasikan batasan yang benar secara manual untuk setiap partisi:sistem melakukan hal itu secara otomatis untuk Anda.

Sayangnya, di PostgreSQL 10 cukup banyak yang dilakukan. Karena kerumitan dan keterbatasan waktu, ada banyak hal dalam implementasi PostgreSQL 10 yang kurang. Robert Haas memberikan ceramah tentangnya di PGConf.EU Warsawa.

Banyak orang bekerja untuk memperbaiki situasi untuk PostgreSQL 11; inilah upaya saya untuk menghitung ulang. Saya membaginya menjadi tiga area:

  1. Fitur partisi baru
  2. Dukungan DDL yang lebih baik untuk tabel yang dipartisi
  3. Pengoptimalan kinerja.

Fitur Partisi Baru

Di PostgreSQL 10, tabel yang dipartisi dapat menjadi RANGE dan DAFTAR mode. Ini adalah alat yang ampuh untuk mendasarkan banyak database dunia nyata, tetapi untuk banyak desain lainnya Anda memerlukan mode baru yang ditambahkan di PostgreSQL 11:HASH partisi . Banyak pelanggan membutuhkan ini, dan Amul Sul bekerja keras untuk mewujudkannya. Berikut ini contoh sederhananya:

CREATE TABLE clients (
client_id INTEGER, name TEXT
) PARTITION BY HASH (client_id);

CREATE TABLE clients_0 PARTITION OF clients
    FOR VALUES WITH (MODULUS 3, REMAINDER 0);
CREATE TABLE clients_1 PARTITION OF clients
    FOR VALUES WITH (MODULUS 3, REMAINDER 1);
CREATE TABLE clients_2 PARTITION OF clients
    FOR VALUES WITH (MODULUS 3, REMAINDER 2);

Tidak wajib menggunakan nilai modulus yang sama untuk semua partisi; ini memungkinkan Anda membuat lebih banyak partisi nanti dan mendistribusikan ulang baris satu partisi pada satu waktu, jika perlu.

Fitur lain yang sangat berguna, ditulis oleh Amit Khandekar adalah kemampuan untuk mengizinkan PERBARUI untuk memindahkan baris dari satu partisi ke partisi lain — yaitu, jika ada perubahan pada nilai kolom partisi, baris secara otomatis dipindahkan ke partisi yang benar. Sebelumnya, operasi itu akan menimbulkan kesalahan.

Fitur baru lainnya, ditulis oleh Amit Langote dan milikmu sungguh , apakah itu MASUKKAN DI PEMBARUAN KONFLIK dapat diterapkan ke tabel yang dipartisi . Sebelumnya perintah ini akan gagal jika menargetkan tabel yang dipartisi. Anda dapat membuatnya bekerja dengan mengetahui secara pasti di partisi mana baris akan berakhir, tetapi itu sangat tidak nyaman. Saya tidak akan membahas detail perintah itu, tetapi jika Anda pernah berharap memiliki UPSERT di Postgres, ini dia. Satu peringatan adalah bahwa UPDATE tindakan tidak boleh memindahkan baris ke partisi lain.

Terakhir, fitur baru yang lucu lainnya di PostgreSQL 11, kali ini oleh Jeevan Ladhe, Beena Emerson, Ashutosh Bapat, Rahila Syed, dan Robert Haas adalah dukungan untuk partisi default dalam tabel yang dipartisi , yaitu, partisi yang menerima semua baris yang tidak muat di salah satu partisi biasa. Namun, meskipun bagus di atas kertas, fitur ini sangat tidak nyaman pada pengaturan produksi karena beberapa operasi memerlukan penguncian yang lebih berat dengan partisi default daripada tanpa. Contoh:membuat partisi baru memerlukan pemindaian partisi default untuk menentukan bahwa tidak ada baris yang ada yang cocok dengan batas partisi baru. Mungkin di masa depan persyaratan kunci ini akan diturunkan, tetapi untuk sementara saran saya jangan menggunakannya.

Dukungan DDL yang lebih baik

Di PostgreSQL 10, DDL tertentu akan menolak bekerja saat diterapkan ke tabel yang dipartisi, dan mengharuskan Anda untuk memproses setiap partisi satu per satu. Di PostgreSQL 11 kami telah memperbaiki beberapa batasan ini, seperti yang diumumkan sebelumnya oleh Simon Riggs. Pertama, Anda sekarang dapat menggunakan CREATE INDEX pada tabel yang dipartisi , fitur yang benar-benar ditulis oleh Anda. Yang ini dapat dilihat sebagai masalah mengurangi kebosanan:alih-alih mengulangi perintah untuk setiap partisi (dan memastikan untuk tidak pernah melupakan setiap partisi baru), Anda dapat melakukannya hanya sekali untuk tabel yang dipartisi induk, dan itu secara otomatis berlaku ke semua partisi, yang ada dan yang akan datang.

Satu hal keren yang perlu diingat adalah pencocokan indeks yang ada di partisi. Seperti yang Anda ketahui, membuat indeks adalah proposisi pemblokiran, jadi semakin sedikit waktu yang dibutuhkan, semakin baik. Saya menulis fitur ini agar indeks yang ada di partisi akan dibandingkan dengan indeks yang dibuat, dan jika ada kecocokan, tidak perlu memindai partisi untuk membuat indeks baru:indeks yang ada akan digunakan.

Bersama-sama dengan ini, juga oleh Anda sendiri, Anda juga dapat membuat UNIK batasan, serta PRIMARY KEY kendala . Dua peringatan:pertama, kunci partisi harus menjadi bagian dari kunci utama. Ini memungkinkan pemeriksaan unik dilakukan secara lokal per partisi, menghindari indeks global. Kedua, tidak mungkin memiliki kunci asing yang mereferensikan kunci utama ini. Saya sedang mengerjakannya untuk PostgreSQL 12.

Hal lain yang dapat Anda lakukan (terima kasih kepada orang yang sama) adalah membuat UNTUK SETIAP ROW pemicu pada tabel yang dipartisi , dan menerapkannya ke semua partisi (yang ada dan yang akan datang). Sebagai efek samping, Anda dapat menunda unik batasan pada tabel yang dipartisi. Satu peringatan:hanya SETELAH pemicu diizinkan, sampai kami mengetahui cara menangani SEBELUM pemicu yang memindahkan baris ke partisi yang berbeda.

Terakhir, tabel yang dipartisi dapat memiliki KUNCI ASING kendala . Ini sangat berguna untuk mempartisi tabel fakta besar sambil menghindari referensi yang menggantung, yang dibenci semua orang. Rekan saya Gabriele Bartolini mencengkeram pangkuan saya ketika dia tahu saya telah menulis dan melakukan ini, berteriak bahwa ini adalah pengubah permainan dan bagaimana saya bisa begitu tidak peka untuk tidak memberi tahu dia tentang hal ini. Saya, saya hanya terus meretas kode untuk bersenang-senang.

Kinerja Kerja

Sebelumnya, kueri pra-pemrosesan untuk mengetahui partisi mana yang tidak dipindai (pengecualian kendala) agak sederhana dan lambat. Ini telah ditingkatkan dengan kerja tim yang mengagumkan yang dilakukan oleh Amit Langote, David Rowley, Beena Emerson, Dilip Kumar untuk memperkenalkan "pemangkasan lebih cepat" terlebih dahulu dan "pemangkasan runtime" berdasarkan itu setelahnya. Hasilnya jauh lebih bertenaga dan lebih cepat (David Rowley sudah dijelaskan di artikel sebelumnya.) Setelah semua upaya ini, pemangkasan partisi diterapkan pada tiga titik dalam kehidupan kueri:

  1. Pada waktu rencana kueri,
  2. Saat parameter kueri diterima,
  3. Pada setiap titik di mana satu node kueri meneruskan nilai sebagai parameter ke node lain.

Ini adalah peningkatan luar biasa dari sistem asli yang hanya dapat diterapkan pada waktu rencana kueri, dan saya yakin ini akan menyenangkan banyak orang.

Anda dapat melihat fitur ini beraksi dengan membandingkan keluaran EXPLAIN untuk kueri sebelum dan setelah mematikan enable_partition_pruning pilihan. Sebagai contoh yang sangat sederhana, bandingkan rencana ini tanpa pemangkasan:

SET enable_partition_pruning TO off;
EXPLAIN (ANALYZE, COSTS off)
SELECT * FROM clientes
WHERE cliente_id = 1234;
                                QUERY PLAN                                
-------------------------------------------------------------------------
 Append (actual time=6.658..10.549 rows=1 loops=1)
   ->  Seq Scan on clientes_1 (actual time=4.724..4.724 rows=0 loops=1)
         Filter: (cliente_id = 1234)
         Rows Removed by Filter: 24978
   ->  Seq Scan on clientes_00 (actual time=1.914..1.914 rows=0 loops=1)
         Filter: (cliente_id = 1234)
         Rows Removed by Filter: 12644
   ->  Seq Scan on clientes_2 (actual time=0.017..1.021 rows=1 loops=1)
         Filter: (cliente_id = 1234)
         Rows Removed by Filter: 12570
   ->  Seq Scan on clientes_3 (actual time=0.746..0.746 rows=0 loops=1)
         Filter: (cliente_id = 1234)
         Rows Removed by Filter: 12448
   ->  Seq Scan on clientes_01 (actual time=0.648..0.648 rows=0 loops=1)
         Filter: (cliente_id = 1234)
         Rows Removed by Filter: 12482
   ->  Seq Scan on clientes_4 (actual time=0.774..0.774 rows=0 loops=1)
         Filter: (cliente_id = 1234)
         Rows Removed by Filter: 12400
   ->  Seq Scan on clientes_5 (actual time=0.717..0.717 rows=0 loops=1)
         Filter: (cliente_id = 1234)
         Rows Removed by Filter: 12477
 Planning Time: 0.375 ms
 Execution Time: 10.603 ms

dengan yang dihasilkan dengan pemangkasan:

EXPLAIN (ANALYZE, COSTS off)
SELECT * FROM clientes
WHERE cliente_id = 1234;
                                QUERY PLAN                               
----------------------------------------------------------------------
 Append (actual time=0.054..2.787 rows=1 loops=1)
   ->  Seq Scan on clientes_2 (actual time=0.052..2.785 rows=1 loops=1)
         Filter: (cliente_id = 1234)
         Rows Removed by Filter: 12570
 Planning Time: 0.292 ms
 Execution Time: 2.822 ms

Saya yakin Anda akan menganggapnya menarik. Anda dapat melihat banyak contoh yang lebih canggih dengan membaca file yang diharapkan dari pengujian regresi.

Item lainnya adalah pengenalan penggabungan partisi, oleh Ashutosh Bapat . Idenya di sini adalah jika Anda memiliki dua tabel yang dipartisi, dan keduanya dipartisi dengan cara yang sama, maka ketika keduanya digabungkan, Anda dapat menggabungkan setiap partisi di satu sisi ke partisi yang cocok di sisi lain; ini jauh lebih baik daripada menggabungkan setiap partisi di sisi ke setiap partisi di sisi lain. Fakta bahwa skema partisi harus sama persis mungkin membuat ini tampak tidak mungkin untuk banyak digunakan di dunia nyata, tetapi dalam kenyataannya ada banyak situasi di mana ini berlaku. Contoh:tabel pesanan dan tabel pesanan_item yang sesuai. Untungnya, sudah ada banyak pekerjaan untuk melonggarkan pembatasan ini.

Item terakhir yang ingin saya sebutkan adalah agregat partisi, oleh Jeevan Chalke, Ashutosh Bapat, dan Robert Haas . Pengoptimalan ini berarti bahwa agregasi yang menyertakan kunci partisi di GROUP BY klausa dapat dieksekusi dengan menggabungkan setiap baris partisi secara terpisah, yang jauh lebih cepat.

Pemikiran Penutup

Setelah perkembangan signifikan dalam siklus ini, PostgreSQL memiliki kisah partisi yang jauh lebih menarik. Meskipun masih banyak perbaikan yang harus dilakukan, terutama untuk meningkatkan kinerja dan konkurensi berbagai operasi yang melibatkan tabel yang dipartisi, sekarang kita berada pada titik di mana partisi deklaratif telah menjadi alat yang sangat berharga untuk melayani banyak kasus penggunaan. Di 2ndQuadrant kami akan terus berkontribusi kode untuk meningkatkan PostgreSQL di area ini dan lainnya, seperti yang telah kami lakukan untuk setiap rilis sejak 8.0.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Kompilasi PL/Proxy dengan PostgresPlus Advance Server 9.1

  2. Cara Membuat Pengguna dengan pgAdmin

  3. Mengapa Postgres tidak menggunakan indeks?

  4. Bagaimana Tanh() Bekerja di PostgreSQL

  5. Pertahankan zona waktu dalam jenis stempel waktu PostgreSQL