توزيع الجداول وتعديلها في Azure Cosmos DB ل PostgreSQL

ينطبق على: Azure Cosmos DB ل PostgreSQL (مدعوم بملحق قاعدة بيانات Citus إلى PostgreSQL)

توزيع الجداول

لإنشاء جدول موزع، تحتاج أولاً إلى تحديد مخطط الجدول. للقيام بذلك، يمكنك تحديد جدول باستخدام عبارة CREATE TABLE بنفس الطريقة التي تفعلها مع جدول PostgreSQL عادي.

CREATE TABLE github_events
(
    event_id bigint,
    event_type text,
    event_public boolean,
    repo_id bigint,
    payload jsonb,
    repo jsonb,
    actor jsonb,
    org jsonb,
    created_at timestamp
);

بعد ذلك، يُمكنك استخدام الدالة create_distributed_table() لتحديد عمود توزيع الجدول وإنشاء أجزاء العامل.

SELECT create_distributed_table('github_events', 'repo_id');

يعلم استدعاء الدالة Azure Cosmos DB ل PostgreSQL بأنه يجب توزيع جدول github_events على العمود repo_id (عن طريق تجزئة قيمة العمود).

ينشئ إجمالي 32 جزءًا بشكل افتراضي، حيث يمتلك كل جزء جزءًا من مساحة التجزئة ويتم نسخه نسخًا متماثلاً استنادًا إلى قيمة التكوين الافتراضية citus.shard_replication_factor. تحتوي النسخ المتماثلة للأجزاء التي تم إنشاؤها على العامل على نفس مخطط الجدول والفهرس وتعريفات القيد مثل الجدول على المنسق. بمُجرد إنشاء النسخ المتماثلة، تحفظ الدالة جميع بيانات التعريف الموزعة على المنسق.

يتم تعيين معرّف جزء فريد لكل جزء تم إنشاؤه وجميع النسخ المتماثلة الخاصة به لها نفس معرّف الجزء. يتم تمثيل الأجزاء على عقدة العامل كجداول PostgreSQL عادية تسمى «tablename_shardid» حيث اسم الجدول هو اسم الجدول الموزع، ومعرّف الجزء هو المعرّف الفريد المعين. يُمكنك الاتصال بمثيلات postgres للعامل لعرض الأوامر أو تشغيلها على الأجزاء الفردية.

أنت الآن جاهز لإدراج البيانات في الجدول الموزع وتشغيل الاستعلامات عليه. يمكنك أيضًا معرفة المزيد حول UDF المُستخدم في هذا القسم في المرجع لغة تعريف البيانات للجدول والجزء.

جداول المراجع

يوزع الأسلوب أعلاه الجداول في أجزاء أفقية متعددة. هناك احتمال آخر وهو توزيع الجداول في جزء واحد ونسخ الجزء نسخًا متماثلاً إلى كل عقدة عامل. تسمى الجداول الموزعة بهذه الطريقة جداول المراجع. يتم استخدامها لتخزين البيانات التي تحتاج إلى الوصول إليها بشكل متكرر بواسطة عقد متعددة في نظام مجموعة.

يتضمن المرشحون الشائعون لجداول المراجع ما يلي:

  • الجداول الأصغر التي تحتاج إلى الانضمام مع جداول موزعة أكبر.
  • الجداول في التطبيقات متعددة المستأجرين التي تفتقر إلى عمود معرّف المستأجر أو غير المقترنة بمستأجر. (أو، في أثناء الترحيل، حتى بالنسبة إلى بعض الجداول المُقترنة بمستأجر.)
  • الجداول التي تحتاج إلى قيود فريدة عبر أعمدة متعددة وهي صغيرة بما يكفي.

على سبيل المثال، افترض أن موقع التجارة الإلكترونية مُتعدد المستأجرين يحتاج إلى حساب ضريبة المبيعات للمعاملات في أي من متاجره. المعلومات الضريبية ليست خاصة بأي مستأجر. من المنطقي وضعها في جدول مشترك. قد يبدو جدول المرجع الذي يركز على الولايات المتحدة كما يلي:

-- a reference table

CREATE TABLE states (
  code char(2) PRIMARY KEY,
  full_name text NOT NULL,
  general_sales_tax numeric(4,3)
);

-- distribute it to all workers

SELECT create_reference_table('states');

الآن يمكن أن تنضم الاستعلامات مثل ضريبة حساب واحدة لعربة التسوق إلى الجدول states دون أي حمل للشبكة، ويمكن إضافة مفتاح خارجي إلى رمز الحالة للتحقق من الصحة بشكل أفضل.

بالإضافة إلى توزيع جدول كجزأ واحد منسوخ نسخا متماثلا، create_reference_table يضع UDF علامة عليه كجدول مرجعي في Azure Cosmos DB لجداول بيانات تعريف PostgreSQL. يقوم Azure Cosmos DB ل PostgreSQL تلقائيا بإجراء عمليات تثبيت على مرحلتين (2PC) لإجراء تعديلات على الجداول التي تم وضع علامة عليها بهذه الطريقة، ما يوفر ضمانات تناسق قوية.

للحصول على مثال آخر لاستخدام جداول المراجع، راجع البرنامج التعليمي لقاعدة البيانات مُتعددة المستأجرين.

توزيع بيانات المنسق

إذا تم تحويل قاعدة بيانات PostgreSQL موجودة إلى عقدة منسق لنظام مجموعة، يمكن توزيع البيانات الموجودة في جداولها بكفاءة وبأقل مقاطعة للتطبيق.

تعمل الدالة create_distributed_table الموضحة سابقًا على كل من الجداول الفارغة وغير الفارغة، وبالنسبة إلى الدالة الأخيرة، فإنها توزع تلقائيًا صفوف الجدول في جميع أنحاء نظام المجموعة. ستعرف ما إذا كانت تنسخ البيانات من خلال وجود الرسالة، «إشعار: نسخ البيانات من الجدول المحلي...» على سبيل المثال:

CREATE TABLE series AS SELECT i FROM generate_series(1,1000000) i;
SELECT create_distributed_table('series', 'i');
NOTICE:  Copying data from local table...
 create_distributed_table
 --------------------------

 (1 row)

يتم حظر عمليات الكتابة على الجدول في أثناء ترحيل البيانات، ويتم التعامل مع عمليات الكتابة المعلقة على أنها استعلامات موزعة بمجرد تثبيت الدالة. (إذا فشلت الدالة، تصبح الاستعلامات محلية مرة أخرى.) يمكن أن تستمر القراءات كالمعتاد وسوف تصبح استعلامات موزعة بمجرد تثبيت الدالة.

عند توزيع الجدولين A وB، حيث يحتوي A على مفتاح خارجي إلى B، قم بتوزيع جدول وجهة المفتاح B أولاً. سوف يؤدي القيام بذلك بترتيب خطأ إلى حدوث خطأ:

ERROR:  cannot create foreign key constraint
DETAIL:  Referenced table must be a distributed table or a reference table.

إذا لم يكن من الممكن التوزيع بالترتيب الصحيح، فقم بإفلات المفاتيح الخارجية، وتوزيع الجداول، وإعادة إنشاء المفاتيح الخارجية.

عند ترحيل البيانات من قاعدة بيانات خارجية، مثل من Amazon RDS إلى Azure Cosmos DB ل PostgreSQL، قم أولا بإنشاء Azure Cosmos DB للجداول الموزعة ل PostgreSQL عبر create_distributed_table، ثم انسخ البيانات إلى الجدول. يؤدي النسخ إلى الجداول الموزعة إلى تجنب نفاد المساحة على عقدة المنسق.

تحديد المواقع المشتركة للجداول

يعني الموقع المشترك وضع الاحتفاظ بالمعلومات ذات الصلة على نفس الأجهزة. وهو يتيح الاستعلامات الفعالة، مع الاستفادة من قابلية التوسع الأفقي لمجموعة البيانات بأكملها. لمزيد من المعلومات، راجع ⁧⁩الموقع المشترك⁧⁩.

يتم تجميع الجداول في مجموعات. للتحكم يدويًا في تعيين مجموعة مواقع مشتركة في الجدول، استخدم المعلمة الاختيارية colocate_with لـ create_distributed_table. إذا كنت لا تهتم بتحديد الموقع المشترك للجدول، فاحذف هذه المعلمة. يتم تعيينه افتراضيًا إلى القيمة 'default'، التي تجمع الجدول مع أي جدول موقع مشترك افتراضي آخر له نفس نوع عمود التوزيع وعدد الأجزاء وعامل النسخ المتماثل. إذا كنت ترغب في قطع هذا الموقع المشترك الضمني أو تحديثه، يمكنك استخدام update_distributed_table_colocation().

-- these tables are implicitly co-located by using the same
-- distribution column type and shard count with the default
-- co-location group

SELECT create_distributed_table('A', 'some_int_col');
SELECT create_distributed_table('B', 'other_int_col');

عندما لا يرتبط جدول جديد بالآخرين في مجموعة الموقع المشترك الضمني الخاصة به، حدد colocated_with => 'none'.

-- not co-located with other tables

SELECT create_distributed_table('A', 'foo', colocate_with => 'none');

سيؤدي تقسيم الجداول غير المرتبطة إلى مجموعات الموقع المشترك الخاصة بها إلى تحسين أداء إعادة التوازن للأجزاء؛ لأنه يجب نقل الأجزاء في نفس المجموعة معًا.

عندما تكون الجداول مرتبطة بالفعل (على سبيل المثال متى سوف يتم ضمها)، يمكن أن يكون من المنطقي أن تقوم بوضعها في موقع مشترك بشكل صريح. تعد مكاسب الوضع في موقع مشترك المناسب أكثر أهمية من أي حمل لإعادة التوازن.

لوضع جداول متعددة في موقع مشترك بشكل صريح، وزع جدولاً ثم ضع الجداول الأخرى في مجموعة الموقع المشترك الخاصة به. على سبيل المثال:

-- distribute stores
SELECT create_distributed_table('stores', 'store_id');

-- add to the same group as stores
SELECT create_distributed_table('orders', 'store_id', colocate_with => 'stores');
SELECT create_distributed_table('products', 'store_id', colocate_with => 'stores');

يتم تخزين معلومات حول مجموعات الموقع المشترك في الجدول pg_dist_colocation، بينما يكشف pg_dist_partition عن الجداول التي تم تعيينها للمجموعات.

إسقاط الجداول

يُمكنك استخدام الأمر PostgreSQL DROP TABLE القياسي لإزالة الجداول الموزعة. كما هو الحال مع الجداول العادية، يزيل DROP TABLE أي فهارس وقواعد ومشغلات وقيود موجودة للجدول الهدف. بالإضافة إلى ذلك، فإنه يسقط أيضًا الأجزاء على عقد العامل وينظف بيانات التعريف الخاصة بها.

DROP TABLE github_events;

تعديل الجداول

ينشر Azure Cosmos DB ل PostgreSQL تلقائيا أنواعا عديدة من عبارات DDL. سوف يؤدي تعديل جدول موزع على عقدة المنسق إلى تحديث الأجزاء على العمال أيضًا. تتطلب عبارات DDL الأخرى نشرًا يدويًا، ويتم حظر بعض العبارات الأخرى مثل أي عبارات من شأنها تعديل عمود توزيع. سوف تؤدي محاولة تشغيل DDL غير مؤهلة للنشر التلقائي إلى ظهور خطأ وترك الجداول على عقدة المنسق دون تغيير.

فيما يلي مرجع لفئات عبارات DDL التي يتم نشرها.

إضافة أو تعديل الأعمدة

ينشر Azure Cosmos DB ل PostgreSQL معظم أوامر ALTER TABLE تلقائيا. تعمل إضافة أعمدة أو تغيير قيمها الافتراضية كما هي في قاعدة بيانات PostgreSQL أحادية الجهاز:

-- Adding a column

ALTER TABLE products ADD COLUMN description text;

-- Changing default value

ALTER TABLE products ALTER COLUMN price SET DEFAULT 7.77;

لا بأس أيضًا بإجراء تغييرات كبيرة على عمود موجود مثل إعادة تسميته أو تغيير نوع البيانات الخاص به. ومع ذلك، لا يمكن تغيير نوع بيانات عمود التوزيع. يحدد هذا العمود كيفية توزيع بيانات الجدول من خلال نظام المجموعة، وسيتطلب تعديل نوع البيانات نقل البيانات.

تؤدي محاولة القيام بذلك إلى حدوث خطأ:

-- assumining store_id is the distribution column
-- for products, and that it has type integer

ALTER TABLE products
ALTER COLUMN store_id TYPE text;

/*
ERROR:  XX000: cannot execute ALTER TABLE command involving partition column
LOCATION:  ErrorIfUnsupportedAlterTableStmt, multi_utility.c:2150
*/

إضافة أو إزالة القيود

يسمح لك استخدام Azure Cosmos DB ل PostgreSQL بالاستمرار في الاستمتاع بسلامة قاعدة بيانات ارتباطية، بما في ذلك قيود قاعدة البيانات (راجع مستندات PostgreSQL). نظرا لطبيعة الأنظمة الموزعة، لن يقوم Azure Cosmos DB ل PostgreSQL بقيود التفرد المرجعية أو التكامل المرجعي بين العقد العاملة.

لإعداد مفتاح خارجي بين الجداول الموزعة مشتركة الموقع، قم بتضمين عمود التوزيع دائمًا في المفتاح. قد يتضمن تضمين عمود التوزيع إنشاء مركب المفتاح.

قد يتم إنشاء مفاتيح خارجية في هذه الحالات:

  • بين جدولين مَحليين (غير موزعين)،
  • بين جدولين مَرجعيين،
  • بين جدولين موزعين مشتركين في الموقع عندما يتضمن المُفتاح عمود التوزيع، أو
  • كجدول موزع يُشير إلى جدول مرجع

المفاتيح الخارجية من جداول المراجع إلى الجداول الموزعة غير معتمدة.

ملاحظة

يجب أن تتضمن المفاتيح الأساسية وقيود التفرد عمود التوزيع. سوف تؤدي إضافتها إلى عمود عدم التوزيع إلى حدوث خطأ

يوضح هذا المثال كيفية إنشاء مفاتيح أساسية وخارجية على الجداول الموزعة:

--
-- Adding a primary key
-- --------------------

-- We'll distribute these tables on the account_id. The ads and clicks
-- tables must use compound keys that include account_id.

ALTER TABLE accounts ADD PRIMARY KEY (id);
ALTER TABLE ads ADD PRIMARY KEY (account_id, id);
ALTER TABLE clicks ADD PRIMARY KEY (account_id, id);

-- Next distribute the tables

SELECT create_distributed_table('accounts', 'id');
SELECT create_distributed_table('ads',      'account_id');
SELECT create_distributed_table('clicks',   'account_id');

--
-- Adding foreign keys
-- -------------------

-- Note that this can happen before or after distribution, as long as
-- there exists a uniqueness constraint on the target column(s) which
-- can only be enforced before distribution.

ALTER TABLE ads ADD CONSTRAINT ads_account_fk
  FOREIGN KEY (account_id) REFERENCES accounts (id);
ALTER TABLE clicks ADD CONSTRAINT clicks_ad_fk
  FOREIGN KEY (account_id, ad_id) REFERENCES ads (account_id, id);

وبالمثل، قم بتضمين عمود التوزيع في قيود التفرد:

-- Suppose we want every ad to use a unique image. Notice we can
-- enforce it only per account when we distribute by account id.

ALTER TABLE ads ADD CONSTRAINT ads_unique_image
  UNIQUE (account_id, image_url);

يُمكن تطبيق قيود غير خالية على أي عمود (توزيع أم لا) لأنها لا تتطلب عمليات بحث بين العمال.

ALTER TABLE ads ALTER COLUMN image_url SET NOT NULL;

استِخدام قيود NOT VALID

في بعض الحالات، قد يكون من المفيد فرض قيود للصفوف الجديدة، مع السماح للصفوف غير المطابقة الحالية بالبقاء دون تغيير. يدعم Azure Cosmos DB ل PostgreSQL هذه الميزة لقيود CHECK والمفاتيح الخارجية، باستخدام تعيين قيد PostgreSQL "NOT VALID".

على سبيل المثال، ضع في اعتبارك تطبيقًا يخزن ملفات تعريف المستخدمين في جدول مرجع.

-- we're using the "text" column type here, but a real application
-- might use "citext" which is available in a postgres contrib module

CREATE TABLE users ( email text PRIMARY KEY );
SELECT create_reference_table('users');

في سياق الوقت تخيل أن عددًا قليلاً من غير العناوين يدخل إلى الجدول.

INSERT INTO users VALUES
   ('foo@example.com'), ('hacker12@aol.com'), ('lol');

نود التحقق من صحة العناوين، ولكن لا يسمح لنا PostgreSQL عادة بإضافة قيد CHECK الذي يفشل للصفوف الموجودة. ومع ذلك فإنه يسمح بالقيد الذي تم وضع علامة غير صالح عليه:

ALTER TABLE users
ADD CONSTRAINT syntactic_email
CHECK (email ~
   '^[a-zA-Z0-9.!#$%&''*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$'
) NOT VALID;

الصفوف الجديدة مَحمية الآن.

INSERT INTO users VALUES ('fake');

/*
ERROR:  new row for relation "users_102010" violates
        check constraint "syntactic_email_102010"
DETAIL:  Failing row contains (fake).
*/

في وقت لاحق، خلال ساعات غير الذروة، يُمكن لمسؤول قاعدة البيانات محاولة إصلاح الصفوف غير الصالحة وإعادة التحقق من صحة القيد.

-- later, attempt to validate all rows
ALTER TABLE users
VALIDATE CONSTRAINT syntactic_email;

تحتوي وثائق PostgreSQL على مزيد من المعلومات حول NOT VALID وVALIDATE CONSTRAINT في قسم ALTER TABLE.

إضافة أو إزالة الفهارس

يدعم Azure Cosmos DB ل PostgreSQL إضافة المؤشرات وإزالتها:

-- Adding an index

CREATE INDEX clicked_at_idx ON clicks USING BRIN (clicked_at);

-- Removing an index

DROP INDEX clicked_at_idx;

إضافة فهرس يأخذ تأمين الكتابة، والذي يمكن أن يكون غير مرغوب فيه في «نظام السجل» متعدد المستأجرين. للتقليل إلى أدنى حد من وقت تعطل التطبيق، قم بإنشاء الفهرس بالتزامن بدلاً من ذلك. يتطلب هذا الأسلوب عملاً إجماليًا أكثر من إنشاء فهرس قياسي ويستغرق وقتًا أطول لإكماله. ومع ذلك، نظراً لأنها تسمح للعمليات العادية بالاستمرار أثناء إنشاء الفهرس، فإن هذه الطريقة مفيدة لإضافة فهارس جديدة في بيئة الإنتاج.

-- Adding an index without locking table writes

CREATE INDEX CONCURRENTLY clicked_at_idx ON clicks USING BRIN (clicked_at);

أنواع ووظائف

يؤدي إنشاء أنواع SQL مخصصة ووظائف معرفة من قبل المستخدم إلى تحويل العقد العاملة. ومع ذلك، فإن إنشاء كائنات قاعدة البيانات هذه في معاملة مع عمليات موزعة ينطوي على مفاضلات.

يعمل Azure Cosmos DB ل PostgreSQL على موازاة العمليات مثل create_distributed_table() عبر الأجزاء باستخدام اتصالات متعددة لكل عامل. في حين أنه عند إنشاء كائن قاعدة بيانات، يقوم Azure Cosmos DB ل PostgreSQL بنشره إلى العقد العاملة باستخدام اتصال واحد لكل عامل. قد يتسبب دمج العمليتين في معاملة واحدة في حدوث مشكلات، لأن الاتصالات المتوازية لن تتمكن من رؤية الكائن الذي تم إنشاؤه عبر اتصال واحد ولكن لم يتم الالتزام به بعد.

ضع في اعتبارك كتلة معاملات تقوم بإنشاء نوع وجدول وتحميل البيانات وتوزيع الجدول:

BEGIN;

-- type creation over a single connection:
CREATE TYPE coordinates AS (x int, y int);
CREATE TABLE positions (object_id text primary key, position coordinates);

-- data loading thus goes over a single connection:
SELECT create_distributed_table(‘positions’, ‘object_id’);

SET client_encoding TO 'UTF8';
\COPY positions FROM ‘positions.csv’

COMMIT;

قبل Citus 11.0، سيؤجل Citus إنشاء النوع على العقد العاملة، ويلتزم به بشكل منفصل عند إنشاء الجدول الموزع. وهذا مكن نسخ البيانات في create_distributed_table() أن يحدث بالتوازي. ومع ذلك، فهذا يعني أيضًا أن النوع لم يكن موجودًا دائمًا في عقد عامل Citus - أو إذا تم التراجع عن المعاملة، فسيظل النوع موجودًا على عقد العامل.

مع Citus 11.0، يتغير السلوك الافتراضي لإعطاء الأولوية لاتساق المخطط بين عقد المنسق والعامل. السلوك الجديد له جانب سلبي: إذا حدث انتشار الكائن بعد أمر موازٍ في نفس المعاملة، فلا يمكن إتمام المعاملة بعد الآن، كما هو موضح بواسطة الخطأ في كتلة التعليمات البرمجية أدناه:

BEGIN;
CREATE TABLE items (key text, value text);
-- parallel data loading:
SELECT create_distributed_table(‘items’, ‘key’);
SET client_encoding TO 'UTF8';
\COPY items FROM ‘items.csv’
CREATE TYPE coordinates AS (x int, y int);

ERROR:  cannot run type command because there was a parallel operation on a distributed table in the transaction

إذا واجهت هذه المشكلة، فهناك حلان بسيطان:

  1. استخدم مجموعة citus.create_object_propagation إلى automatic لتأجيل إنشاء النوع في هذه الحالة، وفي هذه الحالة قد يكون هناك بعض عدم التناسق بين كائنات قاعدة البيانات الموجودة على عقد مختلفة.
  2. استخدم مجموعة citus.multi_shard_modify_mode إلى sequential لتعطيل التوازي لكل عقدة. قد يكون تحميل البيانات في نفس المعاملة أبطأ.

الخطوات التالية