استعلامات تشخيصية مفيدة في Azure Cosmos DB ل PostgreSQL

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

البحث عن العقدة التي تحتوي على بيانات لمستأجرٍ معين

في حالة الاستخدام متعدد المستأجرين، يمكننا تحديد عقدة العامل التي تحتوي على صفوف لمستأجر معين. يقوم Azure Cosmos DB ل PostgreSQL بتجميع صفوف الجداول الموزعة في أجزاء، ويضع كل جزء على عقدة عاملة في نظام المجموعة.

لنفترض أن مستأجري التطبيق الخاص بنا هم مخازن، ونريد العثور على عقدة العامل التي تحتفظ بالبيانات لمعرّف المتجر=4. بمعنى آخر، نود العثور على موضع الجزء الذي يحتوي على صفوف يحتوي عمود توزيعها على القيمة 4:

SELECT shardid, shardstate, shardlength, nodename, nodeport, placementid
  FROM pg_dist_placement AS placement,
       pg_dist_node AS node
 WHERE placement.groupid = node.groupid
   AND node.noderole = 'primary'
   AND shardid = (
     SELECT get_shard_id_for_distribution_column('stores', 4)
   );

يحتوي الإخراج على مضيف ومنفذ قاعدة بياناتِ العامل.

┌─────────┬────────────┬─────────────┬───────────┬──────────┬─────────────┐
│ shardid │ shardstate │ shardlength │ nodename  │ nodeport │ placementid │
├─────────┼────────────┼─────────────┼───────────┼──────────┼─────────────┤
│  102009 │          1 │           0 │ 10.0.0.16 │     5432 │           2 │
└─────────┴────────────┴─────────────┴───────────┴──────────┴─────────────┘

البحث عن العقدة التي تستضيف مخططا موزعا

تقترن المخططات الموزعة تلقائيا بمجموعات التوصيل المشتركة الفردية بحيث يتم تحويل الجداول التي تم إنشاؤها في هذه المخططات إلى جداول موزعة مهيأة بدون مفتاح جزء. يمكنك العثور على مكان وجود مخطط موزع عن طريق الانضمام إلى citus_shards citus_schemas:

select schema_name, nodename, nodeport
  from citus_shards
  join citus_schemas cs
    on cs.colocation_id = citus_shards.colocation_id
 group by 1,2,3;
 schema_name | nodename  | nodeport
-------------+-----------+----------
 a           | localhost |     9701
 b           | localhost |     9702
 with_data   | localhost |     9702

يمكنك أيضا الاستعلام citus_shards مباشرة عن التصفية وصولا إلى نوع جدول المخطط للحصول على قائمة مفصلة لجميع الجداول.

select * from citus_shards where citus_table_type = 'schema';
   table_name   | shardid |      shard_name       | citus_table_type | colocation_id | nodename  | nodeport | shard_size | schema_name | colocation_id | schema_size | schema_owner
----------------+---------+-----------------------+------------------+---------------+-----------+----------+------------+-------------+---------------+-------------+--------------
 a.cities       |  102080 | a.cities_102080       | schema           |             4 | localhost |     9701 |       8192 | a           |             4 | 128 kB      | citus
 a.map_tags     |  102145 | a.map_tags_102145     | schema           |             4 | localhost |     9701 |      32768 | a           |             4 | 128 kB      | citus
 a.measurement  |  102047 | a.measurement_102047  | schema           |             4 | localhost |     9701 |          0 | a           |             4 | 128 kB      | citus
 a.my_table     |  102179 | a.my_table_102179     | schema           |             4 | localhost |     9701 |      16384 | a           |             4 | 128 kB      | citus
 a.people       |  102013 | a.people_102013       | schema           |             4 | localhost |     9701 |      32768 | a           |             4 | 128 kB      | citus
 a.test         |  102008 | a.test_102008         | schema           |             4 | localhost |     9701 |       8192 | a           |             4 | 128 kB      | citus
 a.widgets      |  102146 | a.widgets_102146      | schema           |             4 | localhost |     9701 |      32768 | a           |             4 | 128 kB      | citus
 b.test         |  102009 | b.test_102009         | schema           |             5 | localhost |     9702 |       8192 | b           |             5 | 32 kB       | citus
 b.test_col     |  102012 | b.test_col_102012     | schema           |             5 | localhost |     9702 |      24576 | b           |             5 | 32 kB       | citus
 with_data.test |  102180 | with_data.test_102180 | schema           |            11 | localhost |     9702 |     647168 | with_data   |            11 | 632 kB      | citus

البحث عن عمود التوزيعِ لجدول

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

تحتوي الجداول pg_dist_* الموجودة على عقدة المنسق على بيانات تعريف متنوعة حول قاعدة البيانات الموزعة. على وجه الخصوص، يحتفظ pg_dist_partition بمعلومات حول عمود التوزيع لكل جدول. بإمكانك استخدام دالة أداة مساعدة ملائمة للبحث عن اسم عمود التوزيع من التفاصيل منخفضة المستوى في بيانات التعريف. فيما يلي مثال والإخراج الخاص به:

-- create example table

CREATE TABLE products (
  store_id bigint,
  product_id bigint,
  name text,
  price money,

  CONSTRAINT products_pkey PRIMARY KEY (store_id, product_id)
);

-- pick store_id as distribution column

SELECT create_distributed_table('products', 'store_id');

-- get distribution column name for products table

SELECT column_to_column_name(logicalrelid, partkey) AS dist_col_name
  FROM pg_dist_partition
 WHERE logicalrelid='products'::regclass;

مثال على الإخراج:

┌───────────────┐
│ dist_col_name │
├───────────────┤
│ store_id      │
└───────────────┘

الكشف عن الأقفالِ

يتم تشغيل هذا الاستعلام عبر جميع العقد العاملة وتحديد الأقفال ومدة فتحها والاستعلامات المخالفة:

SELECT run_command_on_workers($cmd$
  SELECT array_agg(
    blocked_statement || ' $ ' || cur_stmt_blocking_proc
    || ' $ ' || cnt::text || ' $ ' || age
  )
  FROM (
    SELECT blocked_activity.query    AS blocked_statement,
           blocking_activity.query   AS cur_stmt_blocking_proc,
           count(*)                  AS cnt,
           age(now(), min(blocked_activity.query_start)) AS "age"
    FROM pg_catalog.pg_locks         blocked_locks
    JOIN pg_catalog.pg_stat_activity blocked_activity
      ON blocked_activity.pid = blocked_locks.pid
    JOIN pg_catalog.pg_locks         blocking_locks
      ON blocking_locks.locktype = blocked_locks.locktype
     AND blocking_locks.DATABASE IS NOT DISTINCT FROM blocked_locks.DATABASE
     AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation
     AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page
     AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple
     AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid
     AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid
     AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid
     AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid
     AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid
     AND blocking_locks.pid != blocked_locks.pid
    JOIN pg_catalog.pg_stat_activity blocking_activity ON blocking_activity.pid = blocking_locks.pid
    WHERE NOT blocked_locks.GRANTED
     AND blocking_locks.GRANTED
    GROUP BY blocked_activity.query,
             blocking_activity.query
    ORDER BY 4
  ) a
$cmd$);

مثال على الإخراج:

┌───────────────────────────────────────────────────────────────────────────────────┐
│                               run_command_on_workers                              │
├───────────────────────────────────────────────────────────────────────────────────┤
│ (10.0.0.16,5432,t,"")                                                             │
│ (10.0.0.20,5432,t,"{""update ads_102277 set name = 'new name' where id = 1; $ sel…│
│…ect * from ads_102277 where id = 1 for update; $ 1 $ 00:00:03.729519""}")         │
└───────────────────────────────────────────────────────────────────────────────────┘

الاستعلام عن حجم القطعِ الخاصة بك

سيوفر لك هذا الاستعلام حجم كل جزءٍ من جدول موزع معين، يسمى my_distributed_table:

SELECT *
FROM run_command_on_shards('my_distributed_table', $cmd$
  SELECT json_build_object(
    'shard_name', '%1$s',
    'size',       pg_size_pretty(pg_table_size('%1$s'))
  );
$cmd$);

مثال على الإخراج:

┌─────────┬─────────┬───────────────────────────────────────────────────────────────────────┐
│ shardid │ success │                                result                                 │
├─────────┼─────────┼───────────────────────────────────────────────────────────────────────┤
│  102008 │ t       │ {"shard_name" : "my_distributed_table_102008", "size" : "2416 kB"}    │
│  102009 │ t       │ {"shard_name" : "my_distributed_table_102009", "size" : "3960 kB"}    │
│  102010 │ t       │ {"shard_name" : "my_distributed_table_102010", "size" : "1624 kB"}    │
│  102011 │ t       │ {"shard_name" : "my_distributed_table_102011", "size" : "4792 kB"}    │
└─────────┴─────────┴───────────────────────────────────────────────────────────────────────┘

الاستعلام عن حجم جميع الجداولِ الموزعة

يحصل هذا الاستعلام على قائمة بالأحجام لكل جدول موزع بالإضافة إلى حجم الفهارس الخاصة بها.

SELECT
  tablename,
  pg_size_pretty(
    citus_total_relation_size(tablename::text)
  ) AS total_size
FROM pg_tables pt
JOIN pg_dist_partition pp
  ON pt.tablename = pp.logicalrelid::text
WHERE schemaname = 'public';

مثال على الإخراج:

┌───────────────┬────────────┐
│   tablename   │ total_size │
├───────────────┼────────────┤
│ github_users  │ 39 MB      │
│ github_events │ 98 MB      │
└───────────────┴────────────┘

لاحظ أن هناك Azure Cosmos DB أخرى لوظائف PostgreSQL للاستعلام عن حجم الجدول الموزع، راجع تحديد حجم الجدول.

تحديد المؤشراتِ غير المستخدمة

سيحدد الاستعلام التالي الفهارس غير المستخدمة على العُقد العاملة لجدول موزع معين (my_distributed_table)

SELECT *
FROM run_command_on_shards('my_distributed_table', $cmd$
  SELECT array_agg(a) as infos
  FROM (
    SELECT (
      schemaname || '.' || relname || '##' || indexrelname || '##'
                 || pg_size_pretty(pg_relation_size(i.indexrelid))::text
                 || '##' || idx_scan::text
    ) AS a
    FROM  pg_stat_user_indexes ui
    JOIN  pg_index i
    ON    ui.indexrelid = i.indexrelid
    WHERE NOT indisunique
    AND   idx_scan < 50
    AND   pg_relation_size(relid) > 5 * 8192
    AND   (schemaname || '.' || relname)::regclass = '%s'::regclass
    ORDER BY
      pg_relation_size(i.indexrelid) / NULLIF(idx_scan, 0) DESC nulls first,
      pg_relation_size(i.indexrelid) DESC
  ) sub
$cmd$);

مثال على الإخراج:

┌─────────┬─────────┬───────────────────────────────────────────────────────────────────────┐
│ shardid │ success │                            result                                     │
├─────────┼─────────┼───────────────────────────────────────────────────────────────────────┤
│  102008 │ t       │                                                                       │
│  102009 │ t       │ {"public.my_distributed_table_102009##some_index_102009##28 MB##0"}   │
│  102010 │ t       │                                                                       │
│  102011 │ t       │                                                                       │
└─────────┴─────────┴───────────────────────────────────────────────────────────────────────┘

مراقبة عددِ اتصالات العميل

يحسب الاستعلام التالي الاتصالات المفتوحة على المنسق، ويجمعها حسب النوع.

SELECT state, count(*)
FROM pg_stat_activity
GROUP BY state;

مثال على الإخراج:

┌────────┬───────┐
│ state  │ count │
├────────┼───────┤
│ active │     3 │
│ idle   │     3 │
│ ∅      │     6 │
└────────┴───────┘

عرض استعلاماتِ النظام

استعلامات نشطة

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

SELECT pid, query, state
  FROM pg_stat_activity
 WHERE state != 'idle';

سبب انتظار الاستعلامات

يمكننا أيضًا الاستعلام لمعرفة الأسباب الأكثر شيوعًا للاستعلامات غير الخاملة التي تنتظر. للحصولِ على شرح للأسباب، تحقق من وثائق PostgreSQL.

SELECT wait_event || ':' || wait_event_type AS type, count(*) AS number_of_occurences
  FROM pg_stat_activity
 WHERE state != 'idle'
GROUP BY wait_event, wait_event_type
ORDER BY number_of_occurences DESC;

مثال على الإخراجِ عند تشغيل pg_sleep في استعلام منفصل بشكل متزامن:

┌─────────────────┬──────────────────────┐
│      type       │ number_of_occurences │
├─────────────────┼──────────────────────┤
│ ∅               │                    1 │
│ PgSleep:Timeout │                    1 │
└─────────────────┴──────────────────────┘

معدل الوصولِ إلى الفهرس

سيوفر لك هذا الاستعلام معدل الوصولِ إلى الفهرس عبر جميع العُقد. معدل الوصول إلى الفهرس مفيد في تحديد عدد المرات التي يتم فيها استخدام الفهارس عند الاستعلام. تعتبر قيمة 95٪ أو أعلى مثالية.

-- on coordinator
SELECT 100 * (sum(idx_blks_hit) - sum(idx_blks_read)) / sum(idx_blks_hit) AS index_hit_rate
  FROM pg_statio_user_indexes;

-- on workers
SELECT nodename, result as index_hit_rate
FROM run_command_on_workers($cmd$
  SELECT 100 * (sum(idx_blks_hit) - sum(idx_blks_read)) / sum(idx_blks_hit) AS index_hit_rate
    FROM pg_statio_user_indexes;
$cmd$);

مثال على الإخراج:

┌───────────┬────────────────┐
│ nodename  │ index_hit_rate │
├───────────┼────────────────┤
│ 10.0.0.16 │ 96.0           │
│ 10.0.0.20 │ 98.0           │
└───────────┴────────────────┘

معدّل الوصول إلى ذاكرة التخزين المؤقت

عادةً ما تصل معظم التطبيقات إلى جزء صغير من إجمالي بياناتها في وقت واحد. يحتفظ PostgreSQL بالبيانات التي يتم الوصول إليها بشكلٍ متكرر في الذاكرة لتجنب القراءة البطيئة من القرص. بإمكانك مشاهدة إحصائيات حوله في طريقة العرض pg_statio_user_tables.

القياس المهم هو النسبة المئوية للبيانات التي تأتي من ذاكرة التخزينِ المؤقت للذاكرة مقابل القرص في حمل العمل الخاص بك:

-- on coordinator
SELECT
  sum(heap_blks_read) AS heap_read,
  sum(heap_blks_hit)  AS heap_hit,
  100 * sum(heap_blks_hit) / (sum(heap_blks_hit) + sum(heap_blks_read)) AS cache_hit_rate
FROM
  pg_statio_user_tables;

-- on workers
SELECT nodename, result as cache_hit_rate
FROM run_command_on_workers($cmd$
  SELECT
    100 * sum(heap_blks_hit) / (sum(heap_blks_hit) + sum(heap_blks_read)) AS cache_hit_rate
  FROM
    pg_statio_user_tables;
$cmd$);

مثال على الإخراج:

┌───────────┬──────────┬─────────────────────┐
│ heap_read │ heap_hit │   cache_hit_rate    │
├───────────┼──────────┼─────────────────────┤
│         1 │      132 │ 99.2481203007518796 │
└───────────┴──────────┴─────────────────────┘

في حال وجدت أنك تتعامل بنسبة أقل بكثير من 99٪، فمن المحتمل أن ترغب في زيادة ذاكرة التخزين المؤقت المتوفرة لقاعدة البيانات الخاصة بك.

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