방안: extension 중 pg_store_plans를 활용 주기적으로 변경된 plan이 있는지 확인한다.
plan 변경 감지 쿼리
WITH plan_changes AS (
SELECT
p.queryid,
s.query,
p.plan AS new_plan,
LAG(p.plan) OVER (PARTITIONBY p.queryid ORDERBY p.calls) AS old_plan
FROM
pg_store_plans p
JOIN
pg_stat_statements s ON p.queryid = s.queryid
)
SELECT
queryid,
query,
old_plan,
new_plan
FROM
plan_changes
WHERE
old_plan ISNOTNULL-- 이전 실행 계획이 존재하는 경우만AND old_plan <> new_plan; -- 실행 계획이 변경된 경우만
pg_store_plans.plan과 pg_stat_statements.queryid를 활용하여 각 SQL의 실행 계획을 추적
LAG(p.plan) OVER (...)을 이용해 이전 실행 계획(old_plan)과 현재 실행 계획(new_plan)을 비교
실행 계획이 변경된 경우만 필터링하여 출력
pg_cron을 이용해서 일정 주기로 해당 쿼리 실행
SELECT cron.schedule(
'0 * * * *', -- 매 정각 실행
$$ INSERTINTO plan_changes_log
SELECT queryid, query, old_plan, new_plan, now()
FROM (
WITH plan_changes AS (
SELECT
p.queryid,
s.query,
p.plan AS new_plan,
LAG(p.plan) OVER (PARTITIONBY p.queryid ORDERBY p.calls) AS old_plan
FROM
pg_store_plans p
JOIN
pg_stat_statements s ON p.queryid = s.queryid
)
SELECT queryid, query, old_plan, new_plan
FROM plan_changes
WHERE old_plan ISNOTNULLAND old_plan <> new_plan
) AS changes;
$$
);
실행계획이 변경되었을 경우
최근 ANALYZE 또는 VACUUM 실행 여부 확인
SELECT relname, last_vacuum, last_analyze
FROM pg_stat_all_tables
WHERE last_analyze ISNOTNULLORDERBY last_analyze DESC;