Baca dalam bahasa Inggris

Bagikan melalui


Memadatkan data dengan tabel kolom di Azure Cosmos DB for PostgreSQL

BERLAKU UNTUK: Azure Cosmos DB for PostgreSQL (didukung oleh ekstensi database Citus ke PostgreSQL)

Azure Cosmos DB for PostgreSQL mendukung penyimpanan tabel kolom khusus tambahan untuk beban kerja analitik dan pergudangan data. Saat kolom (bukan baris) disimpan secara berseberang pada disk, data menjadi lebih mudah dikompresi, dan kueri dapat meminta subset kolom dengan lebih cepat.

Buat tabel

Untuk menggunakan penyimpanan klumnar, tentukan USING columnar saat membuat tabel:

CREATE TABLE contestant (
    handle TEXT,
    birthdate DATE,
    rating INT,
    percentile FLOAT,
    country CHAR(3),
    achievements TEXT[]
) USING columnar;

Azure Cosmos DB for PostgreSQL mengonversi baris menjadi penyimpanan kolumnar di "garis- garis" selama penyisipan. Setiap garis menyimpan satu data transaksi, atau 150000 baris, manapun yang kurang. (Ukuran garis dan parameter lain dari tabel kolumnar dapat diubah dengan fungsi alter_columnar_table_set.)

Misalnya, pernyataan berikut menempatkan kelima baris ke dalam garis yang sama, karena semua nilai disisipkan dalam satu transaksi:

-- insert these values into a single columnar stripe

INSERT INTO contestant VALUES
  ('a','1990-01-10',2090,97.1,'XA','{a}'),
  ('b','1990-11-01',2203,98.1,'XA','{a,b}'),
  ('c','1988-11-01',2907,99.4,'XB','{w,y}'),
  ('d','1985-05-05',2314,98.3,'XB','{}'),
  ('e','1995-05-05',2236,98.2,'XC','{a}');

Yang terbaik adalah membuat garis besar jika memungkinkan, karena Azure Cosmos DB for PostgreSQL mengompresi data kolumnar secara terpisah per stripe. Kita dapat melihat fakta tentang tabel kolumnar kami seperti tingkat kompresi, jumlah garis-garis, dan baris rata-rata per garis dengan menggunakan VACUUM VERBOSE:

VACUUM VERBOSE contestant;
INFO:  statistics for "contestant":
storage id: 10000000000
total file size: 24576, total data size: 248
compression rate: 1.31x
total row count: 5, stripe count: 1, average rows per stripe: 5
chunk count: 6, containing data for dropped columns: 0, zstd compressed: 6

Output menunjukkan bahwa Azure Cosmos DB for PostgreSQL menggunakan algoritma kompresi zstd untuk mendapatkan kompresi data 1,31x. Tingkat kompresi membandingkan a) ukuran data yang dimasukkan seperti yang dipentaskan dalam memori terhadap b) ukuran data yang dikompresi dalam garis akhirnya.

Karena cara ukurnya, tingkat kompresi mungkin atau mungkin tidak cocok dengan perbedaan ukuran antara penyimpanan baris dan kolumnar untuk tabel. Satu-satunya cara untuk benar-benar menemukan perbedaan itu adalah dengan membuat tabel baris dan kolumnar yang berisi data yang sama, dan membandingkan.

Mengukur kompresi

Mari kita buat contoh baru dengan lebih banyak data untuk menjadi tolok ukur penghematan kompresi.

-- first a wide table using row storage
CREATE TABLE perf_row(
  c00 int8, c01 int8, c02 int8, c03 int8, c04 int8, c05 int8, c06 int8, c07 int8, c08 int8, c09 int8,
  c10 int8, c11 int8, c12 int8, c13 int8, c14 int8, c15 int8, c16 int8, c17 int8, c18 int8, c19 int8,
  c20 int8, c21 int8, c22 int8, c23 int8, c24 int8, c25 int8, c26 int8, c27 int8, c28 int8, c29 int8,
  c30 int8, c31 int8, c32 int8, c33 int8, c34 int8, c35 int8, c36 int8, c37 int8, c38 int8, c39 int8,
  c40 int8, c41 int8, c42 int8, c43 int8, c44 int8, c45 int8, c46 int8, c47 int8, c48 int8, c49 int8,
  c50 int8, c51 int8, c52 int8, c53 int8, c54 int8, c55 int8, c56 int8, c57 int8, c58 int8, c59 int8,
  c60 int8, c61 int8, c62 int8, c63 int8, c64 int8, c65 int8, c66 int8, c67 int8, c68 int8, c69 int8,
  c70 int8, c71 int8, c72 int8, c73 int8, c74 int8, c75 int8, c76 int8, c77 int8, c78 int8, c79 int8,
  c80 int8, c81 int8, c82 int8, c83 int8, c84 int8, c85 int8, c86 int8, c87 int8, c88 int8, c89 int8,
  c90 int8, c91 int8, c92 int8, c93 int8, c94 int8, c95 int8, c96 int8, c97 int8, c98 int8, c99 int8
);

-- next a table with identical columns using columnar storage
CREATE TABLE perf_columnar(LIKE perf_row) USING COLUMNAR;

Isi kedua tabel dengan himpunan data besar yang sama:

INSERT INTO perf_row
  SELECT
    g % 00500, g % 01000, g % 01500, g % 02000, g % 02500, g % 03000, g % 03500, g % 04000, g % 04500, g % 05000,
    g % 05500, g % 06000, g % 06500, g % 07000, g % 07500, g % 08000, g % 08500, g % 09000, g % 09500, g % 10000,
    g % 10500, g % 11000, g % 11500, g % 12000, g % 12500, g % 13000, g % 13500, g % 14000, g % 14500, g % 15000,
    g % 15500, g % 16000, g % 16500, g % 17000, g % 17500, g % 18000, g % 18500, g % 19000, g % 19500, g % 20000,
    g % 20500, g % 21000, g % 21500, g % 22000, g % 22500, g % 23000, g % 23500, g % 24000, g % 24500, g % 25000,
    g % 25500, g % 26000, g % 26500, g % 27000, g % 27500, g % 28000, g % 28500, g % 29000, g % 29500, g % 30000,
    g % 30500, g % 31000, g % 31500, g % 32000, g % 32500, g % 33000, g % 33500, g % 34000, g % 34500, g % 35000,
    g % 35500, g % 36000, g % 36500, g % 37000, g % 37500, g % 38000, g % 38500, g % 39000, g % 39500, g % 40000,
    g % 40500, g % 41000, g % 41500, g % 42000, g % 42500, g % 43000, g % 43500, g % 44000, g % 44500, g % 45000,
    g % 45500, g % 46000, g % 46500, g % 47000, g % 47500, g % 48000, g % 48500, g % 49000, g % 49500, g % 50000
  FROM generate_series(1,50000000) g;

INSERT INTO perf_columnar
  SELECT
    g % 00500, g % 01000, g % 01500, g % 02000, g % 02500, g % 03000, g % 03500, g % 04000, g % 04500, g % 05000,
    g % 05500, g % 06000, g % 06500, g % 07000, g % 07500, g % 08000, g % 08500, g % 09000, g % 09500, g % 10000,
    g % 10500, g % 11000, g % 11500, g % 12000, g % 12500, g % 13000, g % 13500, g % 14000, g % 14500, g % 15000,
    g % 15500, g % 16000, g % 16500, g % 17000, g % 17500, g % 18000, g % 18500, g % 19000, g % 19500, g % 20000,
    g % 20500, g % 21000, g % 21500, g % 22000, g % 22500, g % 23000, g % 23500, g % 24000, g % 24500, g % 25000,
    g % 25500, g % 26000, g % 26500, g % 27000, g % 27500, g % 28000, g % 28500, g % 29000, g % 29500, g % 30000,
    g % 30500, g % 31000, g % 31500, g % 32000, g % 32500, g % 33000, g % 33500, g % 34000, g % 34500, g % 35000,
    g % 35500, g % 36000, g % 36500, g % 37000, g % 37500, g % 38000, g % 38500, g % 39000, g % 39500, g % 40000,
    g % 40500, g % 41000, g % 41500, g % 42000, g % 42500, g % 43000, g % 43500, g % 44000, g % 44500, g % 45000,
    g % 45500, g % 46000, g % 46500, g % 47000, g % 47500, g % 48000, g % 48500, g % 49000, g % 49500, g % 50000
  FROM generate_series(1,50000000) g;

VACUUM (FREEZE, ANALYZE) perf_row;
VACUUM (FREEZE, ANALYZE) perf_columnar;

Untuk data ini, Anda dapat melihat rasio kompresi yang lebih baik dari 8X dalam tabel kolumnar.

SELECT pg_total_relation_size('perf_row')::numeric/
       pg_total_relation_size('perf_columnar') AS compression_ratio;
 compression_ratio
--------------------
 8.0196135873627944
(1 row)

Contoh

Penyimpanan kolumnar berfungsi dengan baik dengan partisi tabel. Misalnya, lihat dokumentasi komunitas Citus Mesin, pengarsipan dengan penyimpanan kolumnar.

Gotchas

  • Penyimpanan kolumnar mengompres per garis. Garis-garis dibuat per transaksi, jadi memasukkan satu baris per transaksi akan menempatkan satu baris ke dalam garis-garis mereka sendiri. Kompresi dan kinerja garis-garis baris tunggal akan lebih buruk dari tabel baris. Selalu sisipkan secara massal ke tabel kolumnar.
  • Jika Anda mengacaukan dan kolumnarisasi sekelompok garis-garis kecil, Anda terjebak. Satu-satunya perbaikan adalah membuat tabel kolumnar baru dan menyalin data dari yang asli dalam satu transaksi:
    BEGIN;
    CREATE TABLE foo_compacted (LIKE foo) USING columnar;
    INSERT INTO foo_compacted SELECT * FROM foo;
    DROP TABLE foo;
    ALTER TABLE foo_compacted RENAME TO foo;
    COMMIT;
    
  • Pada dasarnya data yang tidak dapat dikompresi dapat menjadi masalah, meskipun penyimpanan kolumnar masih berguna saat memilih kolom tertentu. Tidak perlu memuat kolom lain ke dalam memori.
  • Pada tabel yang dipartisi dengan campuran partisi baris dan kolom, pembaruan harus ditargetkan dengan hati-hati. Filter mereka untuk menekan hanya partisi baris.
    • Jika operasi ditargetkan pada partisi baris tertentu (misalnya, UPDATE p2 SET i = i + 1), itu akan berhasil; jika ditargetkan pada partisi kolumnar tertentu (misalnya, UPDATE p1 SET i = i + 1), itu akan gagal.
    • Jika operasi ditargetkan pada tabel yang dipartisi dan memiliki klausul WHERE yang mengecualikan semua partisi kolumnar (misalnya UPDATE parent SET i = i + 1 WHERE timestamp = '2020-03-15'), itu akan berhasil.
    • Jika operasi ditargetkan pada tabel yang dipartisi, tetapi tidak memfilter pada kolom kunci partisi, itu akan gagal. Bahkan jika ada klausul WHERE yang cocok dengan baris hanya dalam partisi kolumnar, itu tidak cukup - kunci partisi juga harus difilter.

Batasan

Fitur ini masih memiliki batasan yang signifikan:

  • Pemadatan ada di disk, bukan di memori
  • Tambahkan-saja (tidak ada dukungan UPDATE/DELETE)
  • Tidak ada reklamasi ruang (misalnya, transaksi yang dibatalkan mungkin masih menggunakan ruang disk)
  • Tidak ada dukungan indeks, pemindaian indeks, atau pemindaian indeks bitmap
  • Tidak ada tidscans
  • Tidak ada pemindaian sampel
  • Tidak ada dukungan TOAST (nilai besar didukung sebaris)
  • Tidak ada dukungan untuk pernyataan ON CONFLICT (kecuali tindakan DO NOTHING tanpa target yang ditentukan).
  • Tidak ada dukungan untuk kunci tuple (SELECT ... FOR SHARE, SELECT ... FOR UPDATE)
  • Tidak ada dukungan untuk tingkat isolasi yang dapat diserialkan
  • Dukungan untuk server PostgreSQL versi 12+ saja
  • Tidak ada dukungan untuk kunci asing, batasan unik, atau batasan pengecualian
  • Tidak ada dukungan untuk pendekodean logis
  • Tidak ada dukungan untuk pemindaian paralel intra-simpul
  • Tidak ada dukungan untuk pemicu AFTER ... FOR EACH ROW
  • Tidak ada tabel kolom UNLOGGED
  • Tidak ada tabel kolom TEMPORARY

Langkah berikutnya