Uwaga
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
DOTYCZY:
Usługa Azure Cosmos DB for PostgreSQL (obsługiwana przez rozszerzenie bazy danych Citus do bazy danych PostgreSQL)
Usługa Azure Cosmos DB for PostgreSQL obsługuje magazyn tabel kolumnowych tylko do dołączania na potrzeby obciążeń analitycznych i magazynowania danych. Gdy kolumny (a nie wiersze) są przechowywane stale na dysku, dane stają się bardziej kompresowane, a zapytania mogą szybciej żądać podzestawu kolumn.
Utwórz tabelę
Aby użyć magazynu kolumnowego, określ USING columnar
podczas tworzenia tabeli:
CREATE TABLE contestant (
handle TEXT,
birthdate DATE,
rating INT,
percentile FLOAT,
country CHAR(3),
achievements TEXT[]
) USING columnar;
Usługa Azure Cosmos DB dla PostgreSQL konwertuje wiersze na magazyn kolumnowy w "segmenty" podczas operacji wstawiania. Każdy pasek zawiera jedną wartość danych transakcji lub 150000 wierszy, w zależności od tego, która wartość jest mniejsza. (Rozmiar paska i inne parametry tabeli kolumnowej można zmienić za pomocą funkcji alter_columnar_table_set ).
Na przykład następująca instrukcja umieszcza wszystkie pięć wierszy w tym samym pasku, ponieważ wszystkie wartości są wstawione w jednej transakcji:
-- 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}');
Lepiej tworzyć duże paski, kiedy to możliwe, ponieważ Azure Cosmos DB for PostgreSQL kompresuje dane kolumnowe oddzielnie dla każdego paska. Możemy zobaczyć fakty dotyczące naszej tabeli kolumnowej, takie jak szybkość kompresji, liczba pasków i średnie wiersze na paski przy użyciu polecenia 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
Dane wyjściowe pokazują, że usługa Azure Cosmos DB for PostgreSQL użyła algorytmu kompresji zstd w celu uzyskania kompresji danych 1,31 x. Stopa kompresji porównuje a) rozmiar danych wstawionych do pamięci z b) rozmiarem tych danych skompresowanych w docelowym pasku.
Ze względu na to, jak jest mierzony, współczynnik kompresji może być niezgodny z różnicą rozmiaru między magazynowaniem w wierszach i kolumnach dla tabeli. Jedynym sposobem, aby naprawdę znaleźć tę różnicę, jest utworzenie tabeli wierszy i kolumn, które zawierają te same dane i porównanie.
Mierzenie kompresji
Utwórzmy nowy przykład z większą ilością danych, aby porównać oszczędności kompresji.
-- 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;
Wypełnij obie tabele tym samym dużym zestawem danych:
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;
W przypadku tych danych współczynnik kompresji jest lepszy niż 8X w tabeli kolumnowej.
SELECT pg_total_relation_size('perf_row')::numeric/
pg_total_relation_size('perf_columnar') AS compression_ratio;
compression_ratio
--------------------
8.0196135873627944
(1 row)
Przykład
Przechowywanie kolumnowe działa dobrze z partycjonowaniem tabel. Aby zapoznać się z przykładem, zobacz dokumentację społeczności Citus Engine dotyczącą archiwizacji z wykorzystaniem magazynu kolumnowego.
Pułapki
- Magazyn kolumnowy kompresuje na poziomie pasków. Paski są tworzone na transakcję, więc wstawianie jednego wiersza na transakcję spowoduje umieszczenie pojedynczych wierszy we własnych paskach. Kompresja i wydajność pojedynczych pasm wierszy będą gorsze niż w tabeli wierszy. Zawsze wstaw zbiorczo do tabeli kolumnowej.
- Jeśli zrobisz błąd i poustawiasz grupę małych pasków w kolumny, utkniesz.
Jedyną poprawką jest utworzenie nowej tabeli kolumnowej i skopiowanie danych z oryginału w jednej transakcji:
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;
- Zasadniczo nieskompresowalne dane mogą być problemem, chociaż magazyn kolumnowy jest nadal przydatny podczas wybierania określonych kolumn. Nie trzeba ładować innych kolumn do pamięci.
- W tabeli podzielonej na partycje z kombinacją partycji wierszy i kolumn aktualizacje muszą być dokładnie ukierunkowane. Przefiltruj je tak, aby dotyczyły tylko partycji wierszy.
- Jeśli operacja jest ukierunkowana na określoną partycję wiersza (na przykład
UPDATE p2 SET i = i + 1
), zakończy się powodzeniem. Jeśli zostanie ona skierowana do określonej partycji kolumnowej (na przykładUPDATE p1 SET i = i + 1
), zakończy się niepowodzeniem. - Jeśli operacja jest przeznaczona dla tabeli partycjonowanej i ma klauzulę WHERE, która wyklucza wszystkie partycje kolumnowe (na przykład
UPDATE parent SET i = i + 1 WHERE timestamp = '2020-03-15'
), powiedzie się. - Jeśli operacja jest przeznaczona dla tabeli partycjonowanej, ale nie filtruje kolumn klucza partycji, zakończy się niepowodzeniem. Nawet jeśli istnieją klauzule WHERE, które pasują do wierszy tylko w partycjach kolumnowych, nie wystarcza to — również klucz partycji musi być filtrowany.
- Jeśli operacja jest ukierunkowana na określoną partycję wiersza (na przykład
Ograniczenia
Ta funkcja nadal ma znaczące ograniczenia:
- Kompresja jest na dysku, a nie w pamięci
- Tylko dołączanie (bez możliwości aktualizacji ani usuwania)
- Brak odzyskiwania miejsca (na przykład wycofane transakcje mogą nadal zużywać miejsce na dysku)
- Brak obsługi indeksu, skanowania indeksów ani skanowania indeksów map bitowych
- Brak skanów czasowych
- Brak przykładowych skanów
- Brak obsługi TOAST (duże wartości obsługiwane w linii)
- Brak obsługi instrukcji ON CONFLICT (z wyjątkiem akcji NIE RÓB NIC bez podania celu).
- Brak obsługi blokad krotek (SELECT ... FOR SHARE, SELECT ... FOR UPDATE)
- Brak obsługi poziomu izolacji możliwej do serializacji
- Obsługa tylko serwera PostgreSQL w wersji 12 lub nowszej
- Brak obsługi kluczy obcych, unikatowych ograniczeń ani ograniczeń wykluczeń
- Brak obsługi dekodowania logicznego
- Brak obsługi skanowania równoległego wewnątrz węzła
- Brak obsługi dla wyzwalaczy PO ... DLA KAŻDEGO WIERSZA
- Brak tabel kolumnowych UNLOGGED
- Brak tymczasowych tabel kolumnowych
Następne kroki
- Zobacz przykład przechowywania kolumnowego w samouczku serii czasowej Citus (link zewnętrzny).