PostgreSQL için Azure Cosmos DB'de sütunlu tablolarla verileri sıkıştırma

ŞUNLAR IÇIN GEÇERLIDIR: PostgreSQL için Azure Cosmos DB (PostgreSQL'e citus veritabanı uzantısı tarafından desteklenir)

PostgreSQL için Azure Cosmos DB, analiz ve veri ambarı iş yükleri için yalnızca sütunlu tablo depolamayı destekler. Sütunlar (satırlar yerine) diskte bitişik olarak depolandığında, veriler daha sıkıştırılabilir hale gelir ve sorgular sütunların bir alt kümesini daha hızlı isteyebilir.

Bir tablo oluşturma

Sütunlu depolamayı kullanmak için tablo oluştururken belirtin USING columnar :

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

PostgreSQL için Azure Cosmos DB, ekleme sırasında satırları "şeritler" içinde sütunlu depolamaya dönüştürür. Her şeritte bir işlemin değeri (hangisi daha azsa) 150000 satır bulunur. (Sütunlu tablonun şerit boyutu ve diğer parametreleri alter_columnar_table_set işleviyle değiştirilebilir.)

Örneğin, tüm değerler tek bir işleme eklendiğinden aşağıdaki deyim beş satırın tümünü aynı çizgiye yerleştirir:

-- 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}');

PostgreSQL için Azure Cosmos DB sütunlu verileri şerit başına ayrı ayrı sıkıştırdığından mümkün olduğunda büyük şeritler oluşturmak en iyisidir. sütunlu tablomuzla ilgili sıkıştırma hızı, şerit sayısı ve şerit başına ortalama satır sayısı gibi bilgileri kullanarak VACUUM VERBOSEgörebiliriz:

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

Çıktı, PostgreSQL için Azure Cosmos DB'nin 1,31x veri sıkıştırması elde etmek için zstd sıkıştırma algoritmasını kullandığını gösterir. Sıkıştırma hızı, a) eklenen verilerin bellekte b'ye göre hazırlandığı boyutu) son şeridinde sıkıştırılmış olan verilerin boyutunu karşılaştırır.

Ölçülen yöntem nedeniyle, sıkıştırma oranı tablo için satır ve sütunlu depolama arasındaki boyut farkıyla eşleşebilir veya eşleşmeyebilir. Bu farkı gerçekten bulmanın tek yolu, aynı verileri içeren bir satır ve sütunlu tablo oluşturmak ve karşılaştırmaktır.

Sıkıştırmayı ölçme

Şimdi sıkıştırma tasarruflarını karşılaştırmak için daha fazla veri içeren yeni bir örnek oluşturalım.

-- 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;

Her iki tabloyu da aynı büyük veri kümesiyle doldurun:

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;

Bu veriler için sütunlu tabloda 8X'ten daha iyi bir sıkıştırma oranı görebilirsiniz.

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

Örnek

Sütunlu depolama, tablo bölümleme ile iyi çalışır. Örnek için Citus Engine topluluk belgelerine bakın ve sütunlu depolama ile arşivleme.

Gotchas

  • Sütunlu depolama şerit başına sıkıştırılır. Şeritler işlem başına oluşturulur, bu nedenle işlem başına bir satır eklendiğinde tek satırlar kendi şeritlerine eklenir. Tek satırlı şeritlerin sıkıştırması ve performansı, satır tablosundan daha kötü olacaktır. Her zaman sütunlu tabloya toplu olarak ekleyin.
  • Bir sürü küçük şeridi bozar ve sütunarize ederseniz, sıkışıp kalırsınız. Tek düzeltme, yeni bir sütunlu tablo oluşturmak ve tek bir işlemde özgün tablodan veri kopyalamaktır:
    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;
    
  • Temel olarak sıkıştırılamayan veriler sorun olabilir, ancak sütunlu depolama belirli sütunları seçerken hala yararlıdır. Diğer sütunları belleğe yüklemesi gerekmez.
  • Satır ve sütun bölümlerinin karışımına sahip bölümlenmiş bir tabloda güncelleştirmeler dikkatle hedeflenmelidir. Bunları yalnızca satır bölümlerine isabet etmek için filtreleyin.
    • İşlem belirli bir satır bölümünü (örneğin, UPDATE p2 SET i = i + 1) hedeflediyse başarılı olur; belirtilen sütunlu bir bölüme (örneğin, UPDATE p1 SET i = i + 1) hedefleniyorsa başarısız olur.
    • İşlem bölümlenmiş tabloyu hedefliyorsa ve tüm sütunlu bölümleri (örneğin UPDATE parent SET i = i + 1 WHERE timestamp = '2020-03-15') dışlayan bir WHERE yan tümcesine sahipse başarılı olur.
    • İşlem bölümlenmiş tabloya hedeflenmişse ancak bölüm anahtarı sütunlarına göre filtre uygulamazsa başarısız olur. Yalnızca sütunlu bölümlerdeki satırlarla eşleşen WHERE yan tümceleri olsa bile bu yeterli değildir; bölüm anahtarına da filtre uygulanmış olmalıdır.

Sınırlamalar

Bu özelliğin hala önemli sınırlamaları vardır:

  • Sıkıştırma bellekte değil diskte
  • Yalnızca ekleme (UPDATE/DELETE desteği yok)
  • Alan geri kazanma yok (örneğin, geri alınan işlemler disk alanını kullanmaya devam edebilir)
  • Dizin desteği, dizin taramaları veya bit eşlem dizini taramaları yok
  • Tidscans yok
  • Örnek tarama yok
  • TOAST desteği yok (satır içinde desteklenen büyük değerler)
  • ON CONFLICT deyimleri için destek yoktur (hedef belirtilmemiş HİÇBİR ŞEY YAPMA eylemleri dışında).
  • Tanımlama grubu kilitleri için destek yok (SELECT ... PAYLAŞ IÇIN ... ÖĞESINI SEÇIN. GÜNCELLEŞTIRME IÇIN)
  • Serileştirilebilir yalıtım düzeyi desteği yok
  • Yalnızca PostgreSQL sunucu sürümleri 12+ desteği
  • Yabancı anahtarlar, benzersiz kısıtlamalar veya dışlama kısıtlamaları için destek yok
  • Mantıksal kod çözme desteği yok
  • Düğüm içi paralel tarama desteği yok
  • AFTER için destek yok... HER SATIR TETIKLEYICISİ İçİn
  • UNLOGGED sütunlu tablo yok
  • GEÇİCİ sütunlu tablo yok

Sonraki adımlar