Kolokasi tabel dalam Azure Database for PostgreSQL – Hyperscale (Citus)

BERLAKU UNTUK: Azure Database for PostgreSQL - Hyperscale (Citus)

Kolokasi berarti menyimpan informasi terkait bersama-sama pada simpul yang sama. Kueri dapat berjalan cepat ketika semua data yang diperlukan tersedia tanpa lalu lintas apa pun. Menanyakan data terkait pada simpul yang berbeda memungkinkan kueri berjalan secara efisien secara paralel pada setiap simpul.

Kolokasi data untuk tabel yang didistribusikan hash

Dalam Azure Database for PostgreSQL – Hyperscale (Citus), baris disimpan dalam pecahan jika hash nilai dalam kolom distribusi berada dalam rentang pecahan hash. Pecahan dengan rentang hash yang sama selalu ditempatkan pada simpul yang sama. Baris dengan nilai kolom distribusi yang sama selalu berada pada simpul yang sama di seluruh tabel.

Shards

Contoh praktis dari kolokasi

Pertimbangkan tabel berikut yang mungkin menjadi bagian dari SaaS analisis dari beberapa penyewa web:

CREATE TABLE event (
  tenant_id int,
  event_id bigint,
  page_id int,
  payload jsonb,
  primary key (tenant_id, event_id)
);

CREATE TABLE page (
  tenant_id int,
  page_id int,
  path text,
  primary key (tenant_id, page_id)
);

Sekarang kami ingin menjawab pertanyaan yang mungkin dikeluarkan oleh dasbor yang menghadap pelanggan. Contoh kueri adalah "Kembalikan jumlah kunjungan dalam seminggu terakhir untuk semua halaman yang dimulai dengan '/blog' di penyewa enam."

Jika data kami berada dalam opsi Server Tunggal, kami dapat dengan mudah mengekspresikan kueri kami dengan menggunakan kumpulan operasi relasional yang kaya yang ditawarkan oleh SQL:

SELECT page_id, count(event_id)
FROM
  page
LEFT JOIN  (
  SELECT * FROM event
  WHERE (payload->>'time')::timestamptz >= now() - interval '1 week'
) recent
USING (tenant_id, page_id)
WHERE tenant_id = 6 AND path LIKE '/blog%'
GROUP BY page_id;

Selama kumpulan kerja untuk kueri ini pas dalam memori, tabel server tunggal adalah solusi yang tepat. Mari kita pertimbangkan peluang penskalaan model data dengan opsi penyebaran Hyperscale (Citus).

Mendistribusikan tabel sesuai ID

Kueri server tunggal mulai melambat seiring dengan bertambahnya jumlah penyewa dan data yang disimpan untuk setiap penyewa. Set kerja berhenti pas dalam memori dan CPU menjadi penyempitan.

Dalam hal ini, kita dapat pecahan data di banyak simpul dengan menggunakan Hyperscale (Citus). Pilihan pertama dan terpenting yang perlu kita buat ketika kita memutuskan untuk pecahan adalah kolom distribusi. Mari kita mulai dengan pilihan penggunaan naif event_id untuk tabel acara page_id dan untuk tabel page:

-- naively use event_id and page_id as distribution columns

SELECT create_distributed_table('event', 'event_id');
SELECT create_distributed_table('page', 'page_id');

Ketika data tersebar di berbagai pekerja, kita tidak dapat melakukan gabungan seperti yang kita lakukan pada satu simpul PostgreSQL. Sebaliknya, kita perlu mengeluarkan dua pertanyaan:

-- (Q1) get the relevant page_ids
SELECT page_id FROM page WHERE path LIKE '/blog%' AND tenant_id = 6;

-- (Q2) get the counts
SELECT page_id, count(*) AS count
FROM event
WHERE page_id IN (/*…page IDs from first query…*/)
  AND tenant_id = 6
  AND (payload->>'time')::date >= now() - interval '1 week'
GROUP BY page_id ORDER BY count DESC LIMIT 10;

Setelah itu, hasil dari dua langkah tersebut perlu digabungkan oleh aplikasi.

Menjalankan kueri harus berkonsultasi dengan data dalam pecahan yang tersebar di simpul.

Inefficient queries

Dalam hal ini, distribusi data menciptakan kelemahan substansial:

  • Overhead dari meng-kueri setiap pecahan dan menjalankan beberapa kueri.
  • Overhead Q1 mengembalikan banyak baris ke klien.
  • Q2 menjadi besar.
  • Kebutuhan untuk menulis kueri dalam beberapa langkah memerlukan perubahan dalam aplikasi.

Data tersebar, sehingga kueri dapat disejajarkan. Ini hanya bermanfaat jika jumlah pekerjaan yang dilakukan kueri secara substansial lebih besar daripada overhead meng-kueri banyak pecahan.

Mendistribusikan tabel sesuai penyewa

Dalam Hyperscale (Citus), baris dengan nilai kolom distribusi yang sama dijamin berada pada simpul yang sama. Mulai dari awal, kita dapat membuat tabel kita dengan tenant_id sebagai kolom distribusi.

-- co-locate tables by using a common distribution column
SELECT create_distributed_table('event', 'tenant_id');
SELECT create_distributed_table('page', 'tenant_id', colocate_with => 'event');

Sekarang Hyperscale (Citus) dapat menjawab kueri server tunggal asli tanpa modifikasi (Q1):

SELECT page_id, count(event_id)
FROM
  page
LEFT JOIN  (
  SELECT * FROM event
  WHERE (payload->>'time')::timestamptz >= now() - interval '1 week'
) recent
USING (tenant_id, page_id)
WHERE tenant_id = 6 AND path LIKE '/blog%'
GROUP BY page_id;

Karena filter dan bergabung di tenant_id, Hyperscale (Citus) tahu bahwa seluruh kueri dapat dijawab dengan menggunakan kumpulan pecahan kolokasi yang berisi data untuk penyewa tertentu. Satu simpul PostgreSQL dapat menjawab kueri dalam satu langkah.

Better query

Dalam beberapa kasus, kueri dan skema tabel harus diubah untuk menyertakan ID penyewa dalam batasan unik dan kondisi gabungan. Perubahan ini biasanya mudah.

Langkah berikutnya