Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/enums.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export enum Property {
CTE_NAME = "CTE Name",
CTE_SCAN = "CTE Scan",
DISABLED = "Disabled",
DISK_USAGE = "Disk Usage",
EXCLUSIVE_AVERAGE_IO_READ_SPEED = "*I/O Read Speed (exclusive)",
EXCLUSIVE_AVERAGE_IO_WRITE_SPEED = "*I/O Write Speed (exclusive)",
EXCLUSIVE_AVERAGE_LOCAL_IO_READ_SPEED = "*Local I/O Read Speed (exclusive)",
Expand Down Expand Up @@ -105,6 +106,9 @@ export enum Property {
FUNCTION_NAME = "Function Name",
GROUP_COUNT = "Group Count",
GROUP_KEY = "Group Key",
HASHAGG_BATCHES = "HashAgg Batches",
HASH_BATCHES = "Hash Batches",
HASH_BUCKETS = "Hash Buckets",
HASH_CONDITION = "Hash Cond",
HEAP_FETCHES = "Heap Fetches",
INDEX_NAME = "Index Name",
Expand All @@ -123,12 +127,16 @@ export enum Property {
NODE_ID = "nodeId",
NODE_TYPE = "Node Type",
OPERATION = "Operation",
ORIGINAL_HASH_BATCHES = "Original Hash Batches",
ORIGINAL_HASH_BUCKETS = "Original Hash Buckets",
OUTPUT = "Output",
PARALLEL_AWARE = "Parallel Aware",
PARENT_RELATIONSHIP = "Parent Relationship",
PARTIAL_MODE = "Partial Mode",
PEAK_MEMORY_USAGE = "Peak Memory Usage",
PEAK_SORT_SPACE_USED = "Peak Sort Space Used",
PEV_PLAN_TAG = "plan_",
PLANNED_PARTITIONS = "Planned Partitions",
PLANNER_ESTIMATE_DIRECTION = "*Planner Row Estimate Direction",
PLANNER_ESTIMATE_FACTOR = "*Planner Row Estimate Factor",
PLANS = "Plans",
Expand Down
15 changes: 15 additions & 0 deletions src/filters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ export function formatCost(value: unknown): string {
return (value as number).toLocaleString(undefined, { minimumFractionDigits: 2 })
}

export function formatNumber(value: unknown): string {
if (value === undefined) {
return "N/A"
}
return (value as number).toLocaleString()
}

export function formatRows(value: unknown): string {
if (value === undefined) {
return "N/A"
Expand Down Expand Up @@ -215,6 +222,7 @@ const nodePropFormatters: Partial<Record<Property, Formatter>> = {
[Property.AVERAGE_SUM_IO_WRITE_SPEED]: formatTransferRate,
[Property.AVERAGE_TEMP_IO_READ_SPEED]: formatTransferRate,
[Property.AVERAGE_TEMP_IO_WRITE_SPEED]: formatTransferRate,
[Property.DISK_USAGE]: formatKilobytes,
[Property.EXCLUSIVE_AVERAGE_IO_READ_SPEED]: formatTransferRate,
[Property.EXCLUSIVE_AVERAGE_IO_WRITE_SPEED]: formatTransferRate,
[Property.EXCLUSIVE_AVERAGE_LOCAL_IO_READ_SPEED]: formatTransferRate,
Expand Down Expand Up @@ -245,6 +253,9 @@ const nodePropFormatters: Partial<Record<Property, Formatter>> = {
[Property.EXCLUSIVE_TEMP_WRITTEN_BLOCKS]: formatBlocksHtml,
[Property.FULL_SORT_GROUPS]: formatSortGroups,
[Property.HEAP_FETCHES]: formatRows,
[Property.HASHAGG_BATCHES]: formatNumber,
[Property.HASH_BATCHES]: formatNumber,
[Property.HASH_BUCKETS]: formatNumber,
[Property.IO_READ_TIME]: formatDuration,
[Property.IO_WRITE_TIME]: formatDuration,
[Property.JIT]: formatJit,
Expand All @@ -254,8 +265,12 @@ const nodePropFormatters: Partial<Record<Property, Formatter>> = {
[Property.LOCAL_IO_WRITE_TIME]: formatDuration,
[Property.LOCAL_READ_BLOCKS]: formatBlocksHtml,
[Property.LOCAL_WRITTEN_BLOCKS]: formatBlocksHtml,
[Property.ORIGINAL_HASH_BATCHES]: formatNumber,
[Property.ORIGINAL_HASH_BUCKETS]: formatNumber,
[Property.OUTPUT]: formatList,
[Property.PARALLEL_AWARE]: formatBoolean,
[Property.PEAK_MEMORY_USAGE]: formatKilobytes,
[Property.PLANNED_PARTITIONS]: formatNumber,
[Property.PLANNER_ESTIMATE_DIRECTION]: formatEstimateDirection,
[Property.PLANNER_ESTIMATE_FACTOR]: formatFactor,
[Property.PLAN_ROWS]: formatRows,
Expand Down
2 changes: 1 addition & 1 deletion src/services/__tests__/12-line-wrapped-plans/01-expect
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
"Actual Total Time": 0.062,
"Actual Rows": 2,
"Actual Loops": 1,
"Buckets": 1024,
"Hash Buckets": 1024,
"Plans": [
{
"Node Type": "Seq Scan",
Expand Down
2 changes: 1 addition & 1 deletion src/services/__tests__/12-line-wrapped-plans/02-expect
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
"Actual Total Time": 0.062,
"Actual Rows": 2,
"Actual Loops": 1,
"Buckets": 1024,
"Hash Buckets": 1024,
"Plans": [
{
"Node Type": "Seq Scan",
Expand Down
2 changes: 1 addition & 1 deletion src/services/__tests__/12-line-wrapped-plans/05-expect
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@
"Actual Total Time": 4.997,
"Actual Rows": 10,
"Actual Loops": 3,
"Buckets": 1024,
"Hash Buckets": 1024,
"Shared Hit Blocks": 26,
"Shared Read Blocks": 9,
"Shared Written Blocks": 0,
Expand Down
4 changes: 2 additions & 2 deletions src/services/__tests__/12-line-wrapped-plans/06-expect
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@
"Actual Total Time": 0.555,
"Actual Rows": 10,
"Actual Loops": 3,
"Buckets": 1024,
"Hash Buckets": 1024,
"Shared Hit Blocks": 33,
"Shared Read Blocks": 0,
"Shared Written Blocks": 0,
Expand Down Expand Up @@ -164,7 +164,7 @@
"Actual Total Time": 1.289,
"Actual Rows": 10,
"Actual Loops": 3,
"Buckets": 1024,
"Hash Buckets": 1024,
"Shared Hit Blocks": 14,
"Shared Read Blocks": 0,
"Shared Written Blocks": 0,
Expand Down
4 changes: 2 additions & 2 deletions src/services/__tests__/12-line-wrapped-plans/07-expect
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@
"Actual Total Time": 0.4,
"Actual Rows": 10,
"Actual Loops": 3,
"Buckets": 1024,
"Hash Buckets": 1024,
"Shared Hit Blocks": 33,
"Shared Read Blocks": 0,
"Shared Written Blocks": 0,
Expand Down Expand Up @@ -164,7 +164,7 @@
"Actual Total Time": 0.933,
"Actual Rows": 10,
"Actual Loops": 3,
"Buckets": 1024,
"Hash Buckets": 1024,
"Shared Hit Blocks": 14,
"Shared Read Blocks": 0,
"Shared Written Blocks": 0,
Expand Down
42 changes: 42 additions & 0 deletions src/services/__tests__/26-planned-partitions.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { describe, expect, test } from "vitest"
import { PlanService } from "@/services/plan-service"
import type { IPlanContent } from "@/interfaces"

describe("PlanService", () => {
test("Planned partitions line is correctly parsed", () => {
const planService = new PlanService()
const source = `
HashAggregate (cost=13760592.78..14872410.30 rows=1736877 width=61)
Group Key: ml.offer_type, ml.property_main_type, COALESCE(ml.district_id, '00000000-0000-0000-0000-000000000000'::uuid), COALESCE(ml.sale_price, ml.gross_rent_monthly, ml.rent_net_monthly, '0'::real)
Filter: (array_length(array_agg(ml.id), 1) > 1)
Planned Partitions: 128
-> Seq Scan on post_merged_listings ml (cost=0.00..11025300.36 rows=32660208 width=33)
Filter: (duplicate_id IS NULL)
`
const plan = planService.fromText(source) as IPlanContent
expect(plan.Plan["Planned Partitions"]).toEqual(128)
expect(plan.Plan["HashAgg Batches"]).toBeUndefined()
expect(plan.Plan["Peak Memory Usage"]).toBeUndefined()
expect(plan.Plan["Disk Usage"]).toBeUndefined()
})

test("Planned partitions line is correctly parsed", () => {
const planService = new PlanService()
const source = `
HashAggregate (cost=79468.50..98636.70 rows=940257 width=11) (actual time=231.946..413.626 rows=970675 loops=1)
Group Key: name
Planned Partitions: 32 Batches: 193 Memory Usage: 4153kB Disk Usage: 31752kB
-> Seq Scan on t1 (cost=0.00..15406.00 rows=1000000 width=11) (actual time=0.118..36.474 rows=1000000 loops=1)
Planning Time: 0.201 ms
Execution Time: 438.186 ms
(6 rows)

Time: 438.861 ms
`
const plan = planService.fromText(source) as IPlanContent
expect(plan.Plan["Planned Partitions"]).toEqual(32)
expect(plan.Plan["HashAgg Batches"]).toEqual(193)
expect(plan.Plan["Peak Memory Usage"]).toEqual(4153)
expect(plan.Plan["Disk Usage"]).toEqual(31752)
})
})
23 changes: 23 additions & 0 deletions src/services/__tests__/from-text/45-buckets-expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"Plan": {
"Node Type": "Hash Join",
"Plans": [
{
"Node Type": "Seq Scan"
}, {
"Node Type": "Hash",
"Shared Hit Blocks": 14909,
"Shared Read Blocks": 98728,
"Temp Written Blocks": 88109,
"Hash Buckets": 1048576,
"Hash Batches": 16,
"Peak Memory Usage": 62533,
"Plans": [
{
"Node Type": "Seq Scan"
}
]
}
]
}
}
23 changes: 23 additions & 0 deletions src/services/__tests__/from-text/45-buckets-plan
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------
Hash Join (cost=471037.90..1304640.12 rows=14999862 width=114) (actual time=1480.644..9895.695 rows=15001138 loops=1)
Hash Cond: (details.eid = entetes.eid)
Buffers: shared hit=15940 read=282899, temp read=246065 written=246065
I/O Timings: shared read=242.957, temp read=317.342 write=830.025
-> Seq Scan on details (cost=0.00..335215.62 rows=15001362 width=65) (actual time=0.014..1114.539 rows=15001289 loops=1)
Filter: (b IS NOT NULL)
Buffers: shared hit=1031 read=184171
I/O Timings: shared read=157.615
-> Hash (cost=238637.70..238637.70 rows=9999056 width=57) (actual time=1474.384..1474.385 rows=9999900 loops=1)
Buckets: 1048576 Batches: 16 Memory Usage: 62533kB
Buffers: shared hit=14909 read=98728, temp written=88109
I/O Timings: shared read=85.342, temp write=294.483
-> Seq Scan on entetes (cost=0.00..238637.70 rows=9999056 width=57) (actual time=0.016..567.370 rows=9999900 loops=1)
Filter: (a > 100)
Rows Removed by Filter: 101
Buffers: shared hit=14909 read=98728
I/O Timings: shared read=85.342
Planning:
Buffers: shared hit=8
Planning Time: 0.119 ms
Execution Time: 10244.597 ms
24 changes: 24 additions & 0 deletions src/services/__tests__/from-text/46-buckets-expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"Plan": {
"Node Type": "Aggregate",
"Plans": [
{
"Node Type": "Hash Join",
"Plans": [
{
"Node Type": "Seq Scan"
},
{
"Node Type": "Hash",
"Actual Rows": 1001000,
"Hash Buckets": 262144,
"Original Hash Buckets": 262144,
"Hash Batches": 2048,
"Original Hash Batches": 8,
"Peak Memory Usage": 35157
}
]
}
]
}
}
56 changes: 56 additions & 0 deletions src/services/__tests__/from-text/46-buckets-plan
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
-- source: https://www.postgresql.org/message-id/flat/CA%2BhUKGKWWmf%3DWELLG%3DaUGbcugRaSQbtm0tKYiBut-B2rVKX63g%40mail.gmail.com

SET max_parallel_workers_per_gather = 0;
SET synchronize_seqscans = off;
SET work_mem = '4MB';



CREATE TABLE r AS SELECT generate_series(1, 10000000)::int i;
ANALYZE r;



-- 1k uniform keys + 1m duplicates
CREATE TABLE s1k (i int);
INSERT INTO s1k SELECT generate_series(1, 1000)::int i;
ALTER TABLE s1k SET (autovacuum_enabled = off);
ANALYZE s1k;
INSERT INTO s1k SELECT 42 FROM generate_series(1, 1000000);



EXPLAIN ANALYZE SELECT COUNT(*) FROM r JOIN s1k USING (i);
SET
SET
SET
SELECT 10000000
ANALYZE
CREATE TABLE
INSERT 0 1000
ALTER TABLE
ANALYZE
INSERT 0 1000000
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------
Aggregate (cost=302291.30..302291.31 rows=1 width=8) (actual time=3656.686..3656.688 rows=1.00 loops=1)
Buffers: shared hit=6734 read=41984 dirtied=13621, temp read=49855 written=49855
-> Hash Join (cost=27826.00..300076.30 rows=886000 width=0) (actual time=146.635..3619.685 rows=1001000.00 loops=1)
Hash Cond: (r.i = s1k.i)
Buffers: shared hit=6734 read=41984 dirtied=13621, temp read=49855 written=49855
-> Seq Scan on r (cost=0.00..144294.76 rows=10000676 width=4) (actual time=0.201..1200.806 rows=10000000.00 loops=1)
Buffers: shared hit=2304 read=41984 dirtied=13621
-> Hash (cost=13290.00..13290.00 rows=886000 width=4) (actual time=145.449..145.450 rows=1001000.00 loops=1)
Buckets: 262144 (originally 262144) Batches: 2048 (originally 8) Memory Usage: 35157kB
Buffers: shared hit=4430, temp written=2930
-> Seq Scan on s1k (cost=0.00..13290.00 rows=886000 width=4) (actual time=0.011..61.783 rows=1001000.00 loops=1)
Buffers: shared hit=4430
Planning:
Buffers: shared hit=83 read=9
Planning Time: 0.495 ms
JIT:
Functions: 10
Options: Inlining false, Optimization false, Expressions true, Deforming true
Timing: Generation 0.492 ms (Deform 0.134 ms), Inlining 0.000 ms, Optimization 0.266 ms, Emission 3.684 ms, Total 4.442 ms
Execution Time: 3674.128 ms
(20 rows)
15 changes: 15 additions & 0 deletions src/services/__tests__/from-text/47-planned-partitions-expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"Plan": {
"Node Type": "HashAggregate",
"Planned Partitions": 32,
"HashAgg Batches": 193,
"Peak Memory Usage": 4153,
"Disk Usage": 31752,
"Plans": [
{
"Node Type": "Seq Scan"
}
]
}
}

11 changes: 11 additions & 0 deletions src/services/__tests__/from-text/47-planned-partitions-plan
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
-- taken from https://explain.dalibo.com/plan/bcc3fd5fc7bc771b

HashAggregate (cost=79468.50..98636.70 rows=940257 width=11) (actual time=231.946..413.626 rows=970675 loops=1)
Group Key: name
Planned Partitions: 32 Batches: 193 Memory Usage: 4153kB Disk Usage: 31752kB
-> Seq Scan on t1 (cost=0.00..15406.00 rows=1000000 width=11) (actual time=0.118..36.474 rows=1000000 loops=1)
Planning Time: 0.201 ms
Execution Time: 438.186 ms
(6 rows)

Time: 438.861 ms
Loading
Loading