-
Notifications
You must be signed in to change notification settings - Fork 1
perf: bound Dashboard backfill priority plan #739
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
seonghobae
merged 7 commits into
feat/operations-candidate-priority
from
perf/dashboard-backfill-explain
Aug 26, 2026
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
6aa4088
perf: bound dashboard backfill priority plan
2fb753a
test: report actual explain scan loops
3eea373
fix: skip impossible priority scan
9a3f380
Merge branch 'feat/operations-candidate-priority' of https://github.c…
1aed4e6
fix: audit shared backfill SQL calls
f352414
fix: deduplicate backfill tier transitions
73848b2
docs: record backfill tier snapshot boundary
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,108 @@ | ||
| #!/usr/bin/env python3 | ||
| """Measure the exact backfill candidate query without exposing source rows.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import argparse | ||
| import asyncio | ||
| import json | ||
| import os | ||
| from collections import Counter | ||
| from collections.abc import Iterator, Mapping | ||
| from typing import Any | ||
|
|
||
| import asyncpg | ||
|
|
||
| from backend.app.post_content_queue import POST_CONTENT_BACKFILL_CANDIDATE_SQL, SUCCEEDED | ||
|
|
||
|
|
||
| def _nodes(plan: Mapping[str, Any]) -> Iterator[Mapping[str, Any]]: | ||
| """Yield every PostgreSQL plan node without retaining result rows.""" | ||
| yield plan | ||
| for child in plan.get("Plans", ()): | ||
| yield from _nodes(child) | ||
|
|
||
|
|
||
| def summarize_plan(document: list[Mapping[str, Any]]) -> dict[str, Any]: | ||
| """Project EXPLAIN JSON into non-identifying aggregate plan evidence.""" | ||
| root = document[0] | ||
| nodes = tuple(_nodes(root["Plan"])) | ||
| node_counts = Counter(str(node["Node Type"]) for node in nodes) | ||
| relation_scans = Counter( | ||
| str(node["Relation Name"]) for node in nodes if "Relation Name" in node | ||
| ) | ||
| relation_scan_loops = Counter() | ||
| for node in nodes: | ||
| if "Relation Name" in node: | ||
| relation_scan_loops[str(node["Relation Name"])] += int( | ||
| node.get("Actual Loops", 0) | ||
| ) | ||
| return { | ||
| "planning_time_ms": root.get("Planning Time"), | ||
| "execution_time_ms": root.get("Execution Time"), | ||
| "actual_rows": root["Plan"].get("Actual Rows"), | ||
| "shared_hit_blocks": int(root["Plan"].get("Shared Hit Blocks", 0)), | ||
| "shared_read_blocks": int(root["Plan"].get("Shared Read Blocks", 0)), | ||
| "temp_read_blocks": int(root["Plan"].get("Temp Read Blocks", 0)), | ||
| "temp_written_blocks": int(root["Plan"].get("Temp Written Blocks", 0)), | ||
| "node_counts": dict(sorted(node_counts.items())), | ||
| "relation_scans": dict(sorted(relation_scans.items())), | ||
| "relation_scan_loops": dict(sorted(relation_scan_loops.items())), | ||
| } | ||
|
|
||
|
|
||
| async def _measure( | ||
| dsn: str, | ||
| *, | ||
| limit: int, | ||
| embeddings: bool, | ||
| structure: bool, | ||
| priority: bool, | ||
| ) -> dict[str, Any]: | ||
| """Run EXPLAIN inside a rolled-back transaction and return its summary.""" | ||
| conn = await asyncpg.connect(dsn) | ||
| transaction = conn.transaction() | ||
| await transaction.start() | ||
| try: | ||
| value = await conn.fetchval( | ||
| "EXPLAIN (ANALYZE, BUFFERS, WAL, FORMAT JSON) " | ||
| + POST_CONTENT_BACKFILL_CANDIDATE_SQL, | ||
| SUCCEEDED, | ||
| embeddings, | ||
| structure, | ||
| limit, | ||
| priority, | ||
| ) | ||
| document = json.loads(value) if isinstance(value, str) else value | ||
| return summarize_plan(document) | ||
| finally: | ||
| await transaction.rollback() | ||
| await conn.close() | ||
|
|
||
|
|
||
| def main() -> None: | ||
| """Parse bounded operator inputs and print aggregate JSON only.""" | ||
| parser = argparse.ArgumentParser() | ||
| parser.add_argument("--dsn", default=os.environ.get("DATABASE_URL")) | ||
| parser.add_argument("--limit", type=int, default=200, choices=range(1, 201)) | ||
| parser.add_argument("--embeddings", action="store_true") | ||
| parser.add_argument("--structure", action="store_true") | ||
| parser.add_argument("--tier", choices=("priority", "remaining"), default="priority") | ||
| args = parser.parse_args() | ||
| if not args.dsn: | ||
| parser.error("--dsn or DATABASE_URL is required") | ||
| result = asyncio.run( | ||
| _measure( | ||
| args.dsn, | ||
| limit=args.limit, | ||
| embeddings=args.embeddings, | ||
| structure=args.structure, | ||
| priority=args.tier == "priority", | ||
| ) | ||
| ) | ||
| result["candidate_tier"] = args.tier | ||
| print(json.dumps(result, indent=2, sort_keys=True)) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| main() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| """Tests for non-identifying backfill plan evidence.""" | ||
|
|
||
| from scripts.explain_post_content_backfill import summarize_plan | ||
|
|
||
|
|
||
| def test_summarize_plan_reports_aggregate_buffers_and_relations_only() -> None: | ||
| """The evidence summary contains plan metrics but no source-row values.""" | ||
| result = summarize_plan([{"Planning Time": 1.25, "Execution Time": 2.5, "Plan": {"Node Type": "Limit", "Actual Rows": 12, "Shared Hit Blocks": 2, "Plans": [{"Node Type": "Index Scan", "Relation Name": "source_post", "Actual Loops": 4, "Shared Hit Blocks": 3, "Shared Read Blocks": 1}]}}]) | ||
|
|
||
| assert result == { | ||
| "planning_time_ms": 1.25, | ||
| "execution_time_ms": 2.5, | ||
| "actual_rows": 12, | ||
| "shared_hit_blocks": 2, | ||
| "shared_read_blocks": 0, | ||
| "temp_read_blocks": 0, | ||
| "temp_written_blocks": 0, | ||
| "node_counts": {"Index Scan": 1, "Limit": 1}, | ||
| "relation_scans": {"source_post": 1}, | ||
| "relation_scan_loops": {"source_post": 4}, | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.