מעקב אחר ביצועי מסד נתונים ב-AlloyDB Omni

בחירת גרסה של מאמר העזרה:

בדף הזה מוסבר איך לעקוב אחרי הביצועים של מסד נתונים ב-AlloyDB Omni באמצעות סקריפטים של PostgreSQL observability.

הצגת המצב של תהליכים מחוברים ואירועי המתנה

אפשר לקבוע אילו תהליכים מחוברים למופע AlloyDB Omni ואילו קצוות עורפיים ממתינים לפעילות באמצעות שאילתה בתצוגה pg_stat_activity.

SELECT
    pid,
    datname,
    age(backend_xid) AS age_in_xids,
    now() - xact_start AS xact_age,
    now() - query_start AS query_age,
    state,
    wait_event_type,
    wait_event,
    query_id,
    query
FROM
    pg_stat_activity
WHERE
    state != 'idle'
    AND pid <> pg_backend_pid()
ORDER BY
    4 DESC
LIMIT 10;

הצגת הטבלאות הגדולות ביותר

אפשר לקבוע את הגודל של הטבלאות הגדולות ביותר באמצעות שאילתה בתצוגה pg_stat_user_tables.

SELECT
    oid,
    oid::regclass table_name,
    pg_size_pretty(pg_relation_size(oid)),
    relpages,
    s.seq_scan,
    s.idx_scan
FROM
    pg_class,
    pg_stat_user_tables s
WHERE
    s.relid = oid
    AND oid > 16383
    AND relpages > 100
    AND relkind = 'r'
ORDER BY
    relpages DESC
LIMIT 20;

הצגת סריקות רציפות מובילות

אפשר להציג את הסריקות הרציפות המובילות על ידי שליחת שאילתה לתצוגה pg_stat_user_tables.

SELECT
    relid,
    relname,
    seq_scan,
    pg_size_pretty(pg_relation_size(relid))
FROM
    pg_stat_user_tables
ORDER BY
    seq_scan DESC
LIMIT 15;

צפייה בסריקות המובילות של האינדקס

כדי לראות את הסריקות המובילות של האינדקס, שולחים שאילתה לתצוגה pg_stat_user_tables.

SELECT
    relid,
    relid::regclass table_name,
    idx_scan,
    pg_size_pretty(pg_relation_size(relid))
FROM
    pg_stat_user_tables
WHERE
    idx_scan > 10
ORDER BY
    idx_scan DESC
LIMIT 15;

הצגת העסקאות שהפעולה שלהן נמשכה הכי הרבה זמן

אפשר להציג את העסקאות שהפעילו את התהליך הכי הרבה זמן על ידי שליחת שאילתה לתצוגה pg_stat_activity ובדיקת גיל העסקה.

SELECT
    pid,
    age(backend_xid) AS age_in_xids,
    now() - xact_start AS xact_age,
    now() - query_start AS query_age,
    state,
    query
FROM
    pg_stat_activity
WHERE
    state != 'idle'
ORDER BY
    2 DESC
LIMIT 10;

בדיקת התקדמות השאיבה

כדי לבדוק את ההתקדמות של פעולות הניקוי, אפשר לשלוח שאילתה לתצוגה pg_stat_progress_vacuum ולצרף אותה לתצוגה pg_stat_activity באמצעות מזהי תהליכים.

SELECT
  p.pid,
  now() - a.xact_start AS duration,
  coalesce(wait_event_type ||'.'|| wait_event, 'f') AS waiting,
  CASE
    WHEN a.query ~*'^autovacuum.*to prevent wraparound' THEN 'wraparound'
    WHEN a.query ~*'^vacuum' THEN 'user'
  ELSE
    'regular'
  END AS mode,
  p.datname AS database,
  p.relid::regclass AS table,
  p.phase,
  pg_size_pretty(p.heap_blks_total * current_setting('block_size')::int) AS table_size,
  pg_size_pretty(pg_total_relation_size(relid)) AS total_size,
  pg_size_pretty(p.heap_blks_scanned * current_setting('block_size')::int) AS scanned,
  pg_size_pretty(p.heap_blks_vacuumed * current_setting('block_size')::int) AS vacuumed,
  round(100.0 * p.heap_blks_scanned / p.heap_blks_total, 1) AS scanned_pct,
  round(100.0 * p.heap_blks_vacuumed / p.heap_blks_total, 1) AS vacuumed_pct,
  p.index_vacuum_count,
  round(100.0 * p.num_dead_tuples / p.max_dead_tuples,1) AS dead_pct
FROM pg_stat_progress_vacuum p
JOIN pg_stat_activity a using (pid)
ORDER BY now() - a.xact_start DESC;

הצגת שאילתות אסינכרוניות

כדי לראות שאילתות שמופעלות באופן אסינכרוני, אפשר להריץ שאילתה בתצוגה pg_stat_activity ולסנן שאילתות שהן לא תהליך הליבה.

SELECT
    query,
    leader_pid,
    array_agg(pid) FILTER (WHERE leader_pid != pid) AS members
FROM
    pg_stat_activity
WHERE
    leader_pid IS NOT NULL
GROUP BY
    query,
    leader_pid;

הצגת SQL של נעילת חסימה

כדי לראות פעילות שנחסמה, אפשר להריץ שאילתה בתצוגה pg_locks ולצרף אותה לתצוגה pg_stat_activity.

SELECT blocked_locks.pid     AS blocked_pid,
       blocked_activity.usename  AS blocked_user,
       blocking_locks.pid     AS blocking_pid,
       blocking_activity.usename AS blocking_user,
       blocked_activity.query    AS blocked_statement,
       blocked_activity.wait_event AS blocked_wait_event,
       blocking_activity.wait_event AS blocking_wait_event,
       blocking_activity.query   AS current_statement_in_blocking_process
 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;

קביעת היעילות של גודל work_mem וגודל temp_buffers

כדי לבדוק אם הגודל של work_mem ושל temp_buffers מתאים לצרכים שלכם, אפשר להריץ שאילתה על התצוגה pg_stat_database ולבדוק את הקובץ postgres.log. באמצעות pg_stat_database, מריצים את השאילתה הבאה. אם יש עלייה ב-temp_files או ב-temp_bytes בין ההרצות, כנראה שצריך לבצע אופטימיזציה של work_mem או של temp_buffers.

SELECT
    datname,
    temp_files,
    temp_bytes
FROM
    pg_stat_database;

אחרי שמריצים את הפקודה הזו, בודקים את הקובץ postgres.log כדי לראות אם נעשה שימוש בקבצים זמניים:

LOG: [fd.c:1772] temporary file: path "base/pgsql_tmp/pgsql_tmp4640.1", size 139264

המטרה היא למזער את יצירת הקבצים הזמניים, ולא למנוע אותה לחלוטין. הסיבה לכך היא שהגדרת הערכים work_mem ו-temp_buffers יוצרת איזון בין הזיכרון שזמין במארח לבין מספר החיבורים שדורשים את הזיכרון. כדי להגדיר את הפרמטרים האלה בצורה נכונה, צריך להבין כל עומס עבודה בנפרד.