├── .go-version ├── .travis.yml ├── go.mod ├── Dockerfile ├── .gitignore ├── .golangci.yaml ├── .goreleaser.yml ├── go.sum ├── main.go ├── pkg ├── plan │ ├── plan.go │ └── plan_test.go └── html │ ├── html.go │ ├── html_test.go │ └── template.go ├── README.md ├── docs ├── plan.json ├── flamegraph.html ├── cte.json └── cte_flamegraph.html └── LICENSE /.go-version: -------------------------------------------------------------------------------- 1 | 1.13.1 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.13.x 5 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module pg_flame 2 | 3 | go 1.13 4 | 5 | require github.com/stretchr/testify v1.4.0 6 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.13 2 | 3 | WORKDIR /go/src 4 | 5 | RUN cd /go/src \ 6 | && git clone https://github.com/mgartner/pg_flame.git \ 7 | && cd pg_flame \ 8 | && go build 9 | 10 | ENTRYPOINT [ "pg_flame/pg_flame" ] 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, build with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # The produced binary 15 | pg_flame 16 | 17 | # Common name of flamegraph output 18 | flamegraph.html 19 | 20 | # Distribution directory 21 | dist 22 | -------------------------------------------------------------------------------- /.golangci.yaml: -------------------------------------------------------------------------------- 1 | output: 2 | format: tab 3 | linters: 4 | disable-all: true 5 | enable: 6 | - deadcode 7 | - depguard 8 | - dupl 9 | - goconst 10 | - gocritic 11 | - gocyclo 12 | - gofmt 13 | - goimports 14 | - golint 15 | - gosec 16 | - govet 17 | - ineffassign 18 | - maligned 19 | - misspell 20 | - prealloc 21 | - scopelint 22 | - structcheck 23 | - typecheck 24 | - unconvert 25 | - varcheck 26 | issues: 27 | exclude-use-default: false 28 | max-per-linter: 0 29 | max-same-issues: 0 30 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | # This is an example goreleaser.yaml file with some sane defaults. 2 | # Make sure to check the documentation at http://goreleaser.com 3 | builds: 4 | - env: 5 | - CGO_ENABLED=0 6 | archives: 7 | - replacements: 8 | darwin: Darwin 9 | linux: Linux 10 | 386: i386 11 | amd64: x86_64 12 | checksum: 13 | name_template: 'checksums.txt' 14 | snapshot: 15 | name_template: "{{ .Tag }}-next" 16 | changelog: 17 | sort: asc 18 | brews: 19 | - 20 | name: pg_flame 21 | goarm: 6 22 | github: 23 | owner: mgartner 24 | name: homebrew-tap 25 | folder: Formula 26 | homepage: "https://github.com/mgartner/pg_flame" 27 | description: "A flamegraph generator for Postgres EXPLAIN ANALYZE output." 28 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 2 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 5 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 6 | github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= 7 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 8 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 9 | gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= 10 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 11 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "os" 7 | 8 | "pg_flame/pkg/html" 9 | "pg_flame/pkg/plan" 10 | ) 11 | 12 | var ( 13 | // goreleaser automatically overrides this based on the tag 14 | version = "dev" 15 | hFlag = flag.Bool("h", false, "print help info") 16 | helpFlag = flag.Bool("help", false, "print help info") 17 | ) 18 | 19 | func main() { 20 | flag.Parse() 21 | 22 | if *hFlag || *helpFlag { 23 | printHelp() 24 | } 25 | 26 | p, err := plan.New(os.Stdin) 27 | if err != nil { 28 | handleErr(err) 29 | } 30 | 31 | err = html.Generate(os.Stdout, p) 32 | if err != nil { 33 | handleErr(err) 34 | } 35 | } 36 | 37 | func handleErr(err error) { 38 | fmt.Fprintf(os.Stderr, "Error: %v", err) 39 | os.Exit(1) 40 | } 41 | 42 | func printHelp() { 43 | help := `pg_flame %s 44 | 45 | Turn Postgres query plans into flamegraphs. 46 | 47 | Usage: 48 | 49 | pg_flame [options] 50 | 51 | Without Options: 52 | 53 | Reads a JSON query plan from standard input and writes the 54 | flamegraph html to standard output. 55 | 56 | Options: 57 | 58 | -h, --help print help information 59 | ` 60 | 61 | fmt.Printf(help, version) 62 | os.Exit(0) 63 | } 64 | -------------------------------------------------------------------------------- /pkg/plan/plan.go: -------------------------------------------------------------------------------- 1 | package plan 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "io" 7 | ) 8 | 9 | type Plan struct { 10 | PlanningTime float64 `json:"Planning Time"` 11 | ExecutionTree Node `json:"Plan"` 12 | } 13 | 14 | type Node struct { 15 | Method string `json:"Node Type"` 16 | Table string `json:"Relation Name"` 17 | Alias string `json:"Alias"` 18 | Index string `json:"Index Name"` 19 | ParentRelationship string `json:"Parent Relationship"` 20 | PlanCost float64 `json:"Total Cost"` 21 | PlanRows int `json:"Plan Rows"` 22 | PlanWidth int `json:"Plan Width"` 23 | ActualTotalTime float64 `json:"Actual Total Time"` 24 | ActualRows int `json:"Actual Rows"` 25 | ActualLoops int `json:"Actual Loops"` 26 | Filter string `json:"Filter"` 27 | JoinFilter string `json:"Join Filter"` 28 | HashCond string `json:"Hash Cond"` 29 | IndexCond string `json:"Index Cond"` 30 | RecheckCond string `json:"Recheck Cond"` 31 | BuffersHit int `json:"Shared Hit Blocks"` 32 | BuffersRead int `json:"Shared Read Blocks"` 33 | MemoryUsage int `json:"Peak Memory Usage"` 34 | HashBuckets int `json:"Hash Buckets"` 35 | HashBatches int `json:"Hash Batches"` 36 | SortKey []string `json:"Sort Key"` 37 | SortMethod string `json:"Sort Method"` 38 | SortSpaceUsed int `json:"Sort Space Used"` 39 | SortSpaceType string `json:"Sort Space Type"` 40 | Children []Node `json:"Plans"` 41 | } 42 | 43 | var ErrEmptyPlanJSON = errors.New("empty plan JSON") 44 | var ErrInvalidPlanJSON = errors.New("invalid plan JSON") 45 | 46 | func New(r io.Reader) (Plan, error) { 47 | var plans []Plan 48 | 49 | err := json.NewDecoder(r).Decode(&plans) 50 | if err != nil { 51 | var e *json.UnmarshalTypeError 52 | if errors.As(err, &e) { 53 | err = ErrInvalidPlanJSON 54 | } 55 | return Plan{}, err 56 | } 57 | 58 | if len(plans) < 1 { 59 | return Plan{}, ErrEmptyPlanJSON 60 | } 61 | 62 | return plans[0], nil 63 | } 64 | -------------------------------------------------------------------------------- /pkg/html/html.go: -------------------------------------------------------------------------------- 1 | package html 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | 8 | "pg_flame/pkg/plan" 9 | ) 10 | 11 | type Flame struct { 12 | Name string `json:"name"` 13 | Value float64 `json:"value"` 14 | Time float64 `json:"time"` 15 | Detail string `json:"detail"` 16 | Color string `json:"color"` 17 | InitPlan bool `json:"init_plan"` 18 | Children []Flame `json:"children"` 19 | } 20 | 21 | const detailSpan = "%s" 22 | 23 | const colorPlan = "#00C05A" 24 | const colorInit = "#C0C0C0" 25 | 26 | func Generate(w io.Writer, p plan.Plan) error { 27 | f, err := buildFlame(p) 28 | if err != nil { 29 | return err 30 | } 31 | 32 | err = templateHTML.Execute(w, f) 33 | if err != nil { 34 | return err 35 | } 36 | 37 | return nil 38 | } 39 | 40 | func buildFlame(p plan.Plan) (Flame, error) { 41 | planningFlame := Flame{ 42 | Name: "Query Planning", 43 | Value: p.PlanningTime, 44 | Time: p.PlanningTime, 45 | Detail: fmt.Sprintf(detailSpan, "Time to generate the query plan"), 46 | Color: colorPlan, 47 | } 48 | 49 | executionFlame, err := convertPlanNode(p.ExecutionTree, "") 50 | if err != nil { 51 | return Flame{}, err 52 | } 53 | 54 | return Flame{ 55 | Name: "Total", 56 | Value: planningFlame.Value + executionFlame.Value, 57 | Time: planningFlame.Time + executionFlame.Time, 58 | Detail: fmt.Sprintf(detailSpan, "Includes planning and execution time"), 59 | Children: []Flame{planningFlame, executionFlame}, 60 | }, nil 61 | } 62 | 63 | func convertPlanNode(n plan.Node, color string) (Flame, error) { 64 | initPlan := n.ParentRelationship == "InitPlan" 65 | value := n.ActualTotalTime 66 | 67 | if initPlan { 68 | color = colorInit 69 | } 70 | 71 | var childFlames []Flame 72 | for _, childNode := range n.Children { 73 | 74 | // Pass the color forward for grey InitPlan trees 75 | f, err := convertPlanNode(childNode, color) 76 | if err != nil { 77 | return Flame{}, err 78 | } 79 | 80 | // Add to the total value if the child is an InitPlan node 81 | if f.InitPlan { 82 | value += f.Value 83 | } 84 | 85 | childFlames = append(childFlames, f) 86 | } 87 | 88 | d, err := detail(n) 89 | if err != nil { 90 | return Flame{}, err 91 | } 92 | 93 | return Flame{ 94 | Name: name(n), 95 | Value: value, 96 | Time: n.ActualTotalTime, 97 | Detail: d, 98 | Color: color, 99 | InitPlan: initPlan, 100 | Children: childFlames, 101 | }, nil 102 | } 103 | 104 | func name(n plan.Node) string { 105 | switch { 106 | case n.Table != "" && n.Index != "": 107 | return fmt.Sprintf("%s using %s on %s", n.Method, n.Index, n.Table) 108 | case n.Table != "": 109 | return fmt.Sprintf("%s on %s", n.Method, n.Table) 110 | default: 111 | return n.Method 112 | } 113 | } 114 | 115 | func detail(n plan.Node) (string, error) { 116 | var b bytes.Buffer 117 | 118 | err := templateTable.Execute(&b, n) 119 | if err != nil { 120 | return "", err 121 | } 122 | 123 | return b.String(), nil 124 | } 125 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pg_flame [![Version](https://img.shields.io/badge/version-v1.1-blue.svg)](https://github.com/mgartner/pg_flame/releases) [![Build Status](https://travis-ci.com/mgartner/pg_flame.svg?branch=master)](https://travis-ci.com/mgartner/pg_flame) 2 | 3 | A flamegraph generator for Postgres `EXPLAIN ANALYZE` output. 4 | 5 | 6 | 7 | 8 | 9 | ## Demo 10 | 11 | Try the demo [here](https://mgartner.github.io/pg_flame/flamegraph.html). 12 | 13 | ## Installation 14 | 15 | ### Homebrew 16 | 17 | You can install via Homebrew with the follow command: 18 | 19 | ``` 20 | $ brew install mgartner/tap/pg_flame 21 | ``` 22 | 23 | ### Download pre-compiled binary 24 | 25 | Download one of the compiled binaries [in the releases 26 | tab](https://github.com/mgartner/pg_flame/releases). Once downloaded, move 27 | `pg_flame` into your `$PATH`. 28 | 29 | ### Docker 30 | 31 | Alternatively, if you'd like to use Docker to build the program, you can. 32 | 33 | ``` 34 | $ docker pull mgartner/pg_flame 35 | ``` 36 | 37 | ### Build from source 38 | 39 | If you'd like to build a binary from the source code, run the following 40 | commands. Note that compiling requires Go version 1.13+. 41 | 42 | ``` 43 | $ git clone https://github.com/mgartner/pg_flame.git 44 | $ cd pg_flame 45 | $ go build 46 | ``` 47 | 48 | A `pg_flame` binary will be created that you can place in your `$PATH`. 49 | 50 | ## Usage 51 | 52 | The `pg_flame` program reads a JSON query plan from standard input and writes 53 | the flamegraph HTML to standard ouput. Therefore you can pipe and direct input 54 | and output however you desire. 55 | 56 | ### Example: One-step 57 | 58 | ```bash 59 | $ psql dbname -qAtc 'EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON) SELECT id FROM users' \ 60 | | pg_flame \ 61 | > flamegraph.html \ 62 | && open flamegraph.html 63 | ``` 64 | 65 | ### Example: Multi-step with SQL file 66 | 67 | Create a SQL file with the `EXPLAIN ANALYZE` query. 68 | 69 | ```sql 70 | -- query.sql 71 | EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON) 72 | SELECT id 73 | FROM users 74 | ``` 75 | 76 | Then run the query and save the JSON to a file. 77 | 78 | ```bash 79 | $ psql dbname -qAtf query.sql > plan.json 80 | ``` 81 | 82 | Finally, generate the flamegraph HTML. 83 | 84 | ``` 85 | $ cat plan.json | pg_flame > flamegraph.html 86 | ``` 87 | 88 | ### Example: Docker 89 | 90 | If you've followed the Docker installation steps above, you can pipe query plan 91 | JSON to a container and save the output HTML. 92 | 93 | ``` 94 | $ psql dbname -qAtc 'EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON) SELECT id FROM users' \ 95 | | docker run -i pg_flame \ 96 | > flamegraph.html 97 | ``` 98 | 99 | ## Background 100 | 101 | [Flamegraphs](http://www.brendangregg.com/flamegraphs.html) were invented by 102 | Brendan Gregg to visualize CPU consumption per code-path of profiled software. 103 | They are useful visualization tools in many types of performance 104 | investigations. Flamegraphs have been used to visualize Oracle database 105 | [query 106 | plans](https://blog.tanelpoder.com/posts/visualizing-sql-plan-execution-time-with-flamegraphs/) 107 | and [query 108 | executions](https://externaltable.blogspot.com/2014/05/flame-graphs-for-oracle.html) 109 | , proving useful for debugging slow database queries. 110 | 111 | Pg_flame is in extension of that work for Postgres query plans. It generates a 112 | visual hierarchy of query plans. This visualization identifies the relative 113 | time of each part of a query plan. 114 | 115 | This tool relies on the 116 | [`spiermar/d3-flame-graph`](https://github.com/spiermar/d3-flame-graph) plugin to 117 | generate the flamegraph. 118 | -------------------------------------------------------------------------------- /pkg/html/html_test.go: -------------------------------------------------------------------------------- 1 | package html 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | "pg_flame/pkg/plan" 9 | ) 10 | 11 | func TestNew(t *testing.T) { 12 | 13 | t.Run("writes an HTML flamegraph based on a Flame", func(t *testing.T) { 14 | p := plan.Plan{ 15 | ExecutionTree: plan.Node{ 16 | Table: "bears", 17 | ActualTotalTime: 0.022, 18 | }, 19 | } 20 | 21 | b := new(bytes.Buffer) 22 | 23 | err := Generate(b, p) 24 | 25 | assert.NoError(t, err) 26 | 27 | assert.Contains(t, b.String(), p.ExecutionTree.Table) 28 | }) 29 | 30 | } 31 | 32 | func Test_buildFlame(t *testing.T) { 33 | 34 | t.Run("creates a new Flame from a Plan", func(t *testing.T) { 35 | p := plan.Plan{ 36 | PlanningTime: 0.01, 37 | ExecutionTree: plan.Node{ 38 | Method: "Limit", 39 | ActualTotalTime: 0.123, 40 | Children: []plan.Node{ 41 | { 42 | Method: "Seq Scan", 43 | Table: "bears", 44 | ActualTotalTime: 0.022, 45 | }, 46 | }, 47 | }, 48 | } 49 | 50 | f, err := buildFlame(p) 51 | 52 | assert.NoError(t, err) 53 | 54 | assert.Equal(t, "Total", f.Name) 55 | assert.Equal(t, 0.133, f.Value) 56 | assert.Equal(t, 0.133, f.Time) 57 | assert.Equal(t, "Includes planning and execution time", f.Detail) 58 | 59 | assert.Equal(t, "Query Planning", f.Children[0].Name) 60 | assert.Equal(t, colorPlan, f.Children[0].Color) 61 | assert.Equal(t, 0.01, f.Children[0].Value) 62 | assert.Equal(t, 0.01, f.Children[0].Time) 63 | assert.Equal(t, "Time to generate the query plan", f.Children[0].Detail) 64 | 65 | assert.Equal(t, "Limit", f.Children[1].Name) 66 | assert.Equal(t, 0.123, f.Children[1].Value) 67 | assert.Equal(t, 0.123, f.Children[1].Time) 68 | 69 | assert.Equal(t, "Seq Scan on bears", f.Children[1].Children[0].Name) 70 | assert.Equal(t, 0.022, f.Children[1].Children[0].Value) 71 | assert.Equal(t, 0.022, f.Children[1].Children[0].Time) 72 | }) 73 | 74 | t.Run("handles InitPlan nodes", func(t *testing.T) { 75 | p := plan.Plan{ 76 | ExecutionTree: plan.Node{ 77 | Method: "Seq Scan", 78 | ActualTotalTime: 0.12, 79 | Children: []plan.Node{ 80 | { 81 | Method: "Seq Scan", 82 | Table: "bears", 83 | ParentRelationship: "InitPlan", 84 | ActualTotalTime: 0.2, 85 | Children: []plan.Node{ 86 | { 87 | Method: "Seq Scan", 88 | ActualTotalTime: 0.12, 89 | }, 90 | }, 91 | }, 92 | }, 93 | }, 94 | } 95 | 96 | f, err := buildFlame(p) 97 | 98 | assert.NoError(t, err) 99 | 100 | assert.Equal(t, "Total", f.Name) 101 | assert.Equal(t, 0.32, f.Value) 102 | assert.Equal(t, 0.12, f.Time) 103 | 104 | assert.Equal(t, "Seq Scan", f.Children[1].Name) 105 | assert.Equal(t, 0.32, f.Children[1].Value) 106 | assert.Equal(t, 0.12, f.Children[1].Time) 107 | assert.Equal(t, "", f.Children[1].Color) 108 | assert.False(t, f.Children[1].InitPlan) 109 | 110 | assert.Equal(t, "Seq Scan on bears", f.Children[1].Children[0].Name) 111 | assert.Equal(t, 0.2, f.Children[1].Children[0].Value) 112 | assert.Equal(t, 0.2, f.Children[1].Children[0].Time) 113 | assert.Equal(t, colorInit, f.Children[1].Children[0].Color) 114 | assert.True(t, f.Children[1].Children[0].InitPlan) 115 | 116 | assert.Equal(t, colorInit, f.Children[1].Children[0].Children[0].Color) 117 | }) 118 | 119 | } 120 | 121 | func Test_name(t *testing.T) { 122 | 123 | t.Run("returns the method and table if table exists", func(t *testing.T) { 124 | n := plan.Node{ 125 | Method: "Seq Scan", 126 | Table: "bears", 127 | } 128 | 129 | assert.Equal(t, "Seq Scan on bears", name(n)) 130 | }) 131 | 132 | t.Run("returns the method, index, and table if table exists", func(t *testing.T) { 133 | n := plan.Node{ 134 | Method: "Index Scan", 135 | Table: "bears", 136 | Index: "bears_pkey", 137 | } 138 | 139 | assert.Equal(t, "Index Scan using bears_pkey on bears", name(n)) 140 | }) 141 | 142 | t.Run("returns the method if there is no table", func(t *testing.T) { 143 | n := plan.Node{Method: "Seq Scan"} 144 | 145 | assert.Equal(t, "Seq Scan", name(n)) 146 | }) 147 | 148 | } 149 | 150 | func Test_detail(t *testing.T) { 151 | 152 | t.Run("returns a table of details", func(t *testing.T) { 153 | n := plan.Node{ 154 | Filter: "(id = 123)", 155 | MemoryUsage: 12, 156 | } 157 | 158 | d, err := detail(n) 159 | 160 | assert.NoError(t, err) 161 | 162 | assert.Contains(t, d, n.Filter) 163 | assert.Contains(t, d, "12 kB") 164 | }) 165 | 166 | } 167 | -------------------------------------------------------------------------------- /pkg/plan/plan_test.go: -------------------------------------------------------------------------------- 1 | package plan 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestNew(t *testing.T) { 11 | 12 | t.Run("decodes EXPLAIN ANALYZE plan JSON", func(t *testing.T) { 13 | input := strings.NewReader(planJSON) 14 | 15 | p, err := New(input) 16 | 17 | assert.NoError(t, err) 18 | 19 | assert.Equal(t, "Nested Loop", p.ExecutionTree.Method) 20 | assert.Equal(t, "", p.ExecutionTree.Table) 21 | assert.Equal(t, 0.049, p.ExecutionTree.ActualTotalTime) 22 | 23 | child := p.ExecutionTree.Children[0] 24 | 25 | assert.Equal(t, "Hash Join", child.Method) 26 | assert.Equal(t, "users", child.Table) 27 | assert.Equal(t, "users_pkey", child.Index) 28 | assert.Equal(t, "u", child.Alias) 29 | assert.Equal(t, "Outer", child.ParentRelationship) 30 | 31 | assert.Equal(t, 35.06, child.PlanCost) 32 | assert.Equal(t, 1, child.PlanRows) 33 | assert.Equal(t, 543, child.PlanWidth) 34 | 35 | assert.Equal(t, 0.049, child.ActualTotalTime) 36 | assert.Equal(t, 5, child.ActualRows) 37 | assert.Equal(t, 1, child.ActualLoops) 38 | 39 | assert.Equal(t, "((title)::text ~ '.*sql.*'::text)", child.Filter) 40 | assert.Equal(t, "(id = 123)", child.JoinFilter) 41 | assert.Equal(t, "((p.user_id = c.user_id) AND (p.id = c.post_id))", child.HashCond) 42 | assert.Equal(t, "(id = p.user_id)", child.IndexCond) 43 | assert.Equal(t, "(p.user_id = 123)", child.RecheckCond) 44 | 45 | assert.Equal(t, 5, child.BuffersHit) 46 | assert.Equal(t, 1, child.BuffersRead) 47 | 48 | assert.Equal(t, 1024, child.HashBuckets) 49 | assert.Equal(t, 1, child.HashBatches) 50 | assert.Equal(t, 8, child.MemoryUsage) 51 | 52 | assert.Equal(t, []string{"u.id", "u.email DESC"}, child.SortKey) 53 | assert.Equal(t, "quicksort", child.SortMethod) 54 | assert.Equal(t, 33, child.SortSpaceUsed) 55 | assert.Equal(t, "Memory", child.SortSpaceType) 56 | }) 57 | 58 | t.Run("returns an error with empty plan JSON", func(t *testing.T) { 59 | input := strings.NewReader("[]") 60 | 61 | _, err := New(input) 62 | 63 | assert.Error(t, err) 64 | assert.Equal(t, ErrEmptyPlanJSON, err) 65 | }) 66 | 67 | t.Run("returns an error with invalid plan JSON", func(t *testing.T) { 68 | input := strings.NewReader("{}") 69 | 70 | _, err := New(input) 71 | 72 | assert.Error(t, err) 73 | assert.Equal(t, ErrInvalidPlanJSON, err) 74 | }) 75 | 76 | t.Run("returns an error with invalid JSON syntax", func(t *testing.T) { 77 | input := strings.NewReader("[}") 78 | 79 | _, err := New(input) 80 | 81 | assert.Error(t, err) 82 | }) 83 | 84 | } 85 | 86 | const planJSON = ` 87 | [ 88 | { 89 | "Plan": { 90 | "Node Type": "Nested Loop", 91 | "Parallel Aware": false, 92 | "Join Type": "Inner", 93 | "Startup Cost": 265.38, 94 | "Total Cost": 288.42, 95 | "Plan Rows": 1, 96 | "Plan Width": 539, 97 | "Actual Startup Time": 0.049, 98 | "Actual Total Time": 0.049, 99 | "Actual Rows": 0, 100 | "Actual Loops": 1, 101 | "Inner Unique": true, 102 | "Shared Hit Blocks": 5, 103 | "Shared Read Blocks": 1, 104 | "Shared Dirtied Blocks": 0, 105 | "Shared Written Blocks": 0, 106 | "Local Hit Blocks": 0, 107 | "Local Read Blocks": 0, 108 | "Local Dirtied Blocks": 0, 109 | "Local Written Blocks": 0, 110 | "Temp Read Blocks": 0, 111 | "Temp Written Blocks": 0, 112 | "Plans": [ 113 | { 114 | "Node Type": "Hash Join", 115 | "Relation Name": "users", 116 | "Alias": "u", 117 | "Index Name": "users_pkey", 118 | "Parent Relationship": "Outer", 119 | "Parallel Aware": false, 120 | "Join Type": "Inner", 121 | "Startup Cost": 13.50, 122 | "Total Cost": 35.06, 123 | "Plan Rows": 1, 124 | "Plan Width": 543, 125 | "Actual Startup Time": 0.049, 126 | "Actual Total Time": 0.049, 127 | "Actual Rows": 5, 128 | "Actual Loops": 1, 129 | "Inner Unique": false, 130 | "Filter": "((title)::text ~ '.*sql.*'::text)", 131 | "Hash Cond": "((p.user_id = c.user_id) AND (p.id = c.post_id))", 132 | "Index Cond": "(id = p.user_id)", 133 | "Join Filter": "(id = 123)", 134 | "Recheck Cond": "(p.user_id = 123)", 135 | "Hash Buckets": 1024, 136 | "Hash Batches": 1, 137 | "Peak Memory Usage": 8, 138 | "Shared Hit Blocks": 5, 139 | "Shared Read Blocks": 1, 140 | "Shared Dirtied Blocks": 0, 141 | "Shared Written Blocks": 0, 142 | "Sort Key": ["u.id", "u.email DESC"], 143 | "Sort Method": "quicksort", 144 | "Sort Space Used": 33, 145 | "Sort Space Type": "Memory", 146 | "Local Hit Blocks": 0, 147 | "Local Read Blocks": 0, 148 | "Local Dirtied Blocks": 0, 149 | "Local Written Blocks": 0, 150 | "Temp Read Blocks": 0, 151 | "Temp Written Blocks": 0, 152 | "Plans": [ 153 | ] 154 | } 155 | ] 156 | }, 157 | "Planning Time": 2.523, 158 | "Triggers": [ 159 | ], 160 | "Execution Time": 0.221 161 | } 162 | ] 163 | ` 164 | -------------------------------------------------------------------------------- /docs/plan.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Plan": { 4 | "Node Type": "Sort", 5 | "Parallel Aware": false, 6 | "Startup Cost": 2864.87, 7 | "Total Cost": 2869.01, 8 | "Plan Rows": 1657, 9 | "Plan Width": 33, 10 | "Actual Startup Time": 48.641, 11 | "Actual Total Time": 48.649, 12 | "Actual Rows": 106, 13 | "Actual Loops": 1, 14 | "Sort Key": ["u.id", "u.email DESC"], 15 | "Sort Method": "quicksort", 16 | "Sort Space Used": 33, 17 | "Sort Space Type": "Memory", 18 | "Shared Hit Blocks": 821, 19 | "Shared Read Blocks": 0, 20 | "Shared Dirtied Blocks": 0, 21 | "Shared Written Blocks": 0, 22 | "Local Hit Blocks": 0, 23 | "Local Read Blocks": 0, 24 | "Local Dirtied Blocks": 0, 25 | "Local Written Blocks": 0, 26 | "Temp Read Blocks": 0, 27 | "Temp Written Blocks": 0, 28 | "Plans": [ 29 | { 30 | "Node Type": "Aggregate", 31 | "Strategy": "Hashed", 32 | "Partial Mode": "Simple", 33 | "Parent Relationship": "Outer", 34 | "Parallel Aware": false, 35 | "Startup Cost": 2714.13, 36 | "Total Cost": 2776.27, 37 | "Plan Rows": 1657, 38 | "Plan Width": 33, 39 | "Actual Startup Time": 48.048, 40 | "Actual Total Time": 48.557, 41 | "Actual Rows": 106, 42 | "Actual Loops": 1, 43 | "Group Key": ["u.id"], 44 | "Filter": "(count(*) > 1)", 45 | "Rows Removed by Filter": 4758, 46 | "Shared Hit Blocks": 815, 47 | "Shared Read Blocks": 0, 48 | "Shared Dirtied Blocks": 0, 49 | "Shared Written Blocks": 0, 50 | "Local Hit Blocks": 0, 51 | "Local Read Blocks": 0, 52 | "Local Dirtied Blocks": 0, 53 | "Local Written Blocks": 0, 54 | "Temp Read Blocks": 0, 55 | "Temp Written Blocks": 0, 56 | "Plans": [ 57 | { 58 | "Node Type": "Hash Join", 59 | "Parent Relationship": "Outer", 60 | "Parallel Aware": false, 61 | "Join Type": "Inner", 62 | "Startup Cost": 271.14, 63 | "Total Cost": 2676.85, 64 | "Plan Rows": 4971, 65 | "Plan Width": 25, 66 | "Actual Startup Time": 18.000, 67 | "Actual Total Time": 46.020, 68 | "Actual Rows": 4971, 69 | "Actual Loops": 1, 70 | "Inner Unique": false, 71 | "Hash Cond": "(u.id = posts.user_id)", 72 | "Shared Hit Blocks": 815, 73 | "Shared Read Blocks": 0, 74 | "Shared Dirtied Blocks": 0, 75 | "Shared Written Blocks": 0, 76 | "Local Hit Blocks": 0, 77 | "Local Read Blocks": 0, 78 | "Local Dirtied Blocks": 0, 79 | "Local Written Blocks": 0, 80 | "Temp Read Blocks": 0, 81 | "Temp Written Blocks": 0, 82 | "Plans": [ 83 | { 84 | "Node Type": "Seq Scan", 85 | "Parent Relationship": "Outer", 86 | "Parallel Aware": false, 87 | "Relation Name": "users", 88 | "Alias": "u", 89 | "Startup Cost": 0.00, 90 | "Total Cost": 1731.00, 91 | "Plan Rows": 100000, 92 | "Plan Width": 25, 93 | "Actual Startup Time": 0.015, 94 | "Actual Total Time": 12.836, 95 | "Actual Rows": 100000, 96 | "Actual Loops": 1, 97 | "Shared Hit Blocks": 731, 98 | "Shared Read Blocks": 0, 99 | "Shared Dirtied Blocks": 0, 100 | "Shared Written Blocks": 0, 101 | "Local Hit Blocks": 0, 102 | "Local Read Blocks": 0, 103 | "Local Dirtied Blocks": 0, 104 | "Local Written Blocks": 0, 105 | "Temp Read Blocks": 0, 106 | "Temp Written Blocks": 0 107 | }, 108 | { 109 | "Node Type": "Hash", 110 | "Parent Relationship": "Inner", 111 | "Parallel Aware": false, 112 | "Startup Cost": 209.00, 113 | "Total Cost": 209.00, 114 | "Plan Rows": 4971, 115 | "Plan Width": 4, 116 | "Actual Startup Time": 17.893, 117 | "Actual Total Time": 17.894, 118 | "Actual Rows": 4971, 119 | "Actual Loops": 1, 120 | "Hash Buckets": 8192, 121 | "Original Hash Buckets": 8192, 122 | "Hash Batches": 1, 123 | "Original Hash Batches": 1, 124 | "Peak Memory Usage": 239, 125 | "Shared Hit Blocks": 84, 126 | "Shared Read Blocks": 0, 127 | "Shared Dirtied Blocks": 0, 128 | "Shared Written Blocks": 0, 129 | "Local Hit Blocks": 0, 130 | "Local Read Blocks": 0, 131 | "Local Dirtied Blocks": 0, 132 | "Local Written Blocks": 0, 133 | "Temp Read Blocks": 0, 134 | "Temp Written Blocks": 0, 135 | "Plans": [ 136 | { 137 | "Node Type": "Seq Scan", 138 | "Parent Relationship": "Outer", 139 | "Parallel Aware": false, 140 | "Relation Name": "posts", 141 | "Alias": "posts", 142 | "Startup Cost": 0.00, 143 | "Total Cost": 209.00, 144 | "Plan Rows": 4971, 145 | "Plan Width": 4, 146 | "Actual Startup Time": 0.032, 147 | "Actual Total Time": 16.073, 148 | "Actual Rows": 4971, 149 | "Actual Loops": 1, 150 | "Filter": "((title)::text ~ '.*sql.*'::text)", 151 | "Rows Removed by Filter": 5029, 152 | "Shared Hit Blocks": 84, 153 | "Shared Read Blocks": 0, 154 | "Shared Dirtied Blocks": 0, 155 | "Shared Written Blocks": 0, 156 | "Local Hit Blocks": 0, 157 | "Local Read Blocks": 0, 158 | "Local Dirtied Blocks": 0, 159 | "Local Written Blocks": 0, 160 | "Temp Read Blocks": 0, 161 | "Temp Written Blocks": 0 162 | } 163 | ] 164 | } 165 | ] 166 | } 167 | ] 168 | } 169 | ] 170 | }, 171 | "Planning Time": 1.641, 172 | "Triggers": [ 173 | ], 174 | "Execution Time": 48.942 175 | } 176 | ] 177 | -------------------------------------------------------------------------------- /pkg/html/template.go: -------------------------------------------------------------------------------- 1 | package html 2 | 3 | import ( 4 | "html/template" 5 | ) 6 | 7 | var templateHTML *template.Template = template.Must(template.New("html").Parse(` 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 62 | 63 | pg_flame 64 | 65 | 66 | 70 | 71 | 72 |
73 |
74 | 86 | 89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 | 97 | 98 | 99 | 100 | 101 | 158 | 159 | 160 | `)) 161 | 162 | var templateTable *template.Template = template.Must(template.New("table").Parse(` 163 | 164 | 165 | {{if .Method}} 166 | 167 | 168 | 169 | 170 | {{end}} 171 | {{if .Table}} 172 | 173 | 174 | 175 | 176 | {{end}} 177 | {{if .Index}} 178 | 179 | 180 | 181 | 182 | {{end}} 183 | {{if .Alias}} 184 | 185 | 186 | 187 | 188 | {{end}} 189 | {{if .ParentRelationship}} 190 | 191 | 192 | 193 | 194 | {{end}} 195 | {{if .PlanCost}} 196 | 197 | 198 | 199 | 200 | {{end}} 201 | {{if .PlanRows}} 202 | 203 | 204 | 205 | 206 | {{end}} 207 | {{if .PlanWidth}} 208 | 209 | 210 | 211 | 212 | {{end}} 213 | {{if .ActualTotalTime}} 214 | 215 | 216 | 217 | 218 | {{end}} 219 | {{if .ActualRows}} 220 | 221 | 222 | 223 | 224 | {{end}} 225 | {{if .ActualLoops}} 226 | 227 | 228 | 229 | 230 | {{end}} 231 | {{if .Filter}} 232 | 233 | 234 | 235 | 236 | {{end}} 237 | {{if .JoinFilter}} 238 | 239 | 240 | 241 | 242 | {{end}} 243 | {{if .HashCond}} 244 | 245 | 246 | 247 | 248 | {{end}} 249 | {{if .IndexCond}} 250 | 251 | 252 | 253 | 254 | {{end}} 255 | {{if .RecheckCond}} 256 | 257 | 258 | 259 | 260 | {{end}} 261 | {{if .BuffersHit}} 262 | 263 | 264 | 265 | 266 | {{end}} 267 | {{if .BuffersRead}} 268 | 269 | 270 | 271 | 272 | {{end}} 273 | {{if .HashBuckets}} 274 | 275 | 276 | 277 | 278 | {{end}} 279 | {{if .HashBatches}} 280 | 281 | 282 | 283 | 284 | {{end}} 285 | {{if .MemoryUsage}} 286 | 287 | 288 | 289 | 290 | {{end}} 291 | {{if .SortKey}} 292 | 293 | 294 | 295 | 296 | {{end}} 297 | {{if .SortMethod}} 298 | 299 | 300 | 301 | 302 | {{end}} 303 | {{if .SortSpaceUsed}} 304 | 305 | 306 | 307 | 308 | {{end}} 309 | {{if .SortSpaceType}} 310 | 311 | 312 | 313 | 314 | {{end}} 315 | 316 |
Method{{.Method}}
Table{{.Table}}
Index{{.Index}}
Alias{{.Alias}}
Parent Relationship{{.ParentRelationship}}
Plan Cost{{.PlanCost}}
Plan Rows{{.PlanRows}}
Plan Width{{.PlanWidth}}
Actual Total Time{{.ActualTotalTime}} ms
Actual Rows{{.ActualRows}}
Actual Loops{{.ActualLoops}}
Filter{{.Filter}}
Join Filter{{.JoinFilter}}
Hash Cond{{.HashCond}}
Index Cond{{.IndexCond}}
Recheck Cond{{.RecheckCond}}
Buffers Shared Hit{{.BuffersHit}}
Buffers Shared Read{{.BuffersRead}}
Hash Buckets{{.HashBuckets}}
Hash Batches{{.HashBatches}}
Memory Usage{{.MemoryUsage}} kB
Sort Key{{.SortKey}}
Sort Method{{.SortMethod}}
Sort Space Used{{.SortSpaceUsed}} kB
Sort Space Type{{.SortSpaceType}}
317 | `)) 318 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /docs/flamegraph.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 56 | 57 | pg_flame 58 | 59 | 60 | 61 | 62 | 63 |
64 |
65 | 77 | 80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 | 88 | 89 | 90 | 91 | 92 | 149 | 150 | 151 | -------------------------------------------------------------------------------- /docs/cte.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Plan": { 4 | "Node Type": "Aggregate", 5 | "Strategy": "Sorted", 6 | "Partial Mode": "Simple", 7 | "Parallel Aware": false, 8 | "Startup Cost": 15552.51, 9 | "Total Cost": 15554.36, 10 | "Plan Rows": 1, 11 | "Plan Width": 33, 12 | "Actual Startup Time": 755.383, 13 | "Actual Total Time": 755.383, 14 | "Actual Rows": 0, 15 | "Actual Loops": 1, 16 | "Group Key": ["u.id"], 17 | "Filter": "(count(*) > 1)", 18 | "Rows Removed by Filter": 0, 19 | "Shared Hit Blocks": 2957, 20 | "Shared Read Blocks": 0, 21 | "Shared Dirtied Blocks": 0, 22 | "Shared Written Blocks": 0, 23 | "Local Hit Blocks": 0, 24 | "Local Read Blocks": 0, 25 | "Local Dirtied Blocks": 0, 26 | "Local Written Blocks": 0, 27 | "Temp Read Blocks": 0, 28 | "Temp Written Blocks": 0, 29 | "Plans": [ 30 | { 31 | "Node Type": "Seq Scan", 32 | "Parent Relationship": "InitPlan", 33 | "Subplan Name": "CTE sql_posts", 34 | "Parallel Aware": false, 35 | "Relation Name": "posts", 36 | "Alias": "posts", 37 | "Startup Cost": 0.00, 38 | "Total Cost": 209.00, 39 | "Plan Rows": 4971, 40 | "Plan Width": 36, 41 | "Actual Startup Time": 0.023, 42 | "Actual Total Time": 0.023, 43 | "Actual Rows": 1, 44 | "Actual Loops": 1, 45 | "Filter": "((title)::text ~ '.*sql.*'::text)", 46 | "Rows Removed by Filter": 1, 47 | "Shared Hit Blocks": 1, 48 | "Shared Read Blocks": 0, 49 | "Shared Dirtied Blocks": 0, 50 | "Shared Written Blocks": 0, 51 | "Local Hit Blocks": 0, 52 | "Local Read Blocks": 0, 53 | "Local Dirtied Blocks": 0, 54 | "Local Written Blocks": 0, 55 | "Temp Read Blocks": 0, 56 | "Temp Written Blocks": 0 57 | }, 58 | { 59 | "Node Type": "Seq Scan", 60 | "Parent Relationship": "InitPlan", 61 | "Subplan Name": "CTE postgres_posts", 62 | "Parallel Aware": false, 63 | "Relation Name": "posts", 64 | "Alias": "posts_1", 65 | "Startup Cost": 0.00, 66 | "Total Cost": 209.00, 67 | "Plan Rows": 2481, 68 | "Plan Width": 36, 69 | "Actual Startup Time": 0.032, 70 | "Actual Total Time": 0.032, 71 | "Actual Rows": 1, 72 | "Actual Loops": 1, 73 | "Filter": "((title)::text ~ '.*postgres.*'::text)", 74 | "Rows Removed by Filter": 13, 75 | "Shared Hit Blocks": 1, 76 | "Shared Read Blocks": 0, 77 | "Shared Dirtied Blocks": 0, 78 | "Shared Written Blocks": 0, 79 | "Local Hit Blocks": 0, 80 | "Local Read Blocks": 0, 81 | "Local Dirtied Blocks": 0, 82 | "Local Written Blocks": 0, 83 | "Temp Read Blocks": 0, 84 | "Temp Written Blocks": 0 85 | }, 86 | { 87 | "Node Type": "Seq Scan", 88 | "Parent Relationship": "InitPlan", 89 | "Subplan Name": "CTE database_posts", 90 | "Parallel Aware": false, 91 | "Relation Name": "posts", 92 | "Alias": "posts_2", 93 | "Startup Cost": 0.00, 94 | "Total Cost": 209.00, 95 | "Plan Rows": 2548, 96 | "Plan Width": 36, 97 | "Actual Startup Time": 0.010, 98 | "Actual Total Time": 0.010, 99 | "Actual Rows": 1, 100 | "Actual Loops": 1, 101 | "Filter": "((title)::text ~ '.*databases.*'::text)", 102 | "Rows Removed by Filter": 0, 103 | "Shared Hit Blocks": 1, 104 | "Shared Read Blocks": 0, 105 | "Shared Dirtied Blocks": 0, 106 | "Shared Written Blocks": 0, 107 | "Local Hit Blocks": 0, 108 | "Local Read Blocks": 0, 109 | "Local Dirtied Blocks": 0, 110 | "Local Written Blocks": 0, 111 | "Temp Read Blocks": 0, 112 | "Temp Written Blocks": 0 113 | }, 114 | { 115 | "Node Type": "Nested Loop", 116 | "Parent Relationship": "InitPlan", 117 | "Subplan Name": "CTE performance_comments", 118 | "Parallel Aware": false, 119 | "Join Type": "Inner", 120 | "Startup Cost": 0.29, 121 | "Total Cost": 2242.31, 122 | "Plan Rows": 1, 123 | "Plan Width": 25, 124 | "Actual Startup Time": 223.165, 125 | "Actual Total Time": 223.165, 126 | "Actual Rows": 0, 127 | "Actual Loops": 1, 128 | "Inner Unique": true, 129 | "Shared Hit Blocks": 984, 130 | "Shared Read Blocks": 0, 131 | "Shared Dirtied Blocks": 0, 132 | "Shared Written Blocks": 0, 133 | "Local Hit Blocks": 0, 134 | "Local Read Blocks": 0, 135 | "Local Dirtied Blocks": 0, 136 | "Local Written Blocks": 0, 137 | "Temp Read Blocks": 0, 138 | "Temp Written Blocks": 0, 139 | "Plans": [ 140 | { 141 | "Node Type": "Seq Scan", 142 | "Parent Relationship": "Outer", 143 | "Parallel Aware": false, 144 | "Relation Name": "comments", 145 | "Alias": "c", 146 | "Startup Cost": 0.00, 147 | "Total Cost": 2234.00, 148 | "Plan Rows": 1, 149 | "Plan Width": 4, 150 | "Actual Startup Time": 223.164, 151 | "Actual Total Time": 223.164, 152 | "Actual Rows": 0, 153 | "Actual Loops": 1, 154 | "Filter": "((body)::text ~ '.*performance.*'::text)", 155 | "Rows Removed by Filter": 100000, 156 | "Shared Hit Blocks": 984, 157 | "Shared Read Blocks": 0, 158 | "Shared Dirtied Blocks": 0, 159 | "Shared Written Blocks": 0, 160 | "Local Hit Blocks": 0, 161 | "Local Read Blocks": 0, 162 | "Local Dirtied Blocks": 0, 163 | "Local Written Blocks": 0, 164 | "Temp Read Blocks": 0, 165 | "Temp Written Blocks": 0 166 | }, 167 | { 168 | "Node Type": "Index Scan", 169 | "Parent Relationship": "Inner", 170 | "Parallel Aware": false, 171 | "Scan Direction": "Forward", 172 | "Index Name": "users_pkey", 173 | "Relation Name": "users", 174 | "Alias": "u_1", 175 | "Startup Cost": 0.29, 176 | "Total Cost": 8.31, 177 | "Plan Rows": 1, 178 | "Plan Width": 25, 179 | "Actual Startup Time": 0.000, 180 | "Actual Total Time": 0.000, 181 | "Actual Rows": 0, 182 | "Actual Loops": 0, 183 | "Index Cond": "(id = c.user_id)", 184 | "Rows Removed by Index Recheck": 0, 185 | "Shared Hit Blocks": 0, 186 | "Shared Read Blocks": 0, 187 | "Shared Dirtied Blocks": 0, 188 | "Shared Written Blocks": 0, 189 | "Local Hit Blocks": 0, 190 | "Local Read Blocks": 0, 191 | "Local Dirtied Blocks": 0, 192 | "Local Written Blocks": 0, 193 | "Temp Read Blocks": 0, 194 | "Temp Written Blocks": 0 195 | } 196 | ] 197 | }, 198 | { 199 | "Node Type": "Hash Join", 200 | "Parent Relationship": "InitPlan", 201 | "Subplan Name": "CTE testing_comments", 202 | "Parallel Aware": false, 203 | "Join Type": "Inner", 204 | "Startup Cost": 2861.59, 205 | "Total Cost": 5594.66, 206 | "Plan Rows": 50207, 207 | "Plan Width": 25, 208 | "Actual Startup Time": 252.949, 209 | "Actual Total Time": 252.949, 210 | "Actual Rows": 1, 211 | "Actual Loops": 1, 212 | "Inner Unique": false, 213 | "Hash Cond": "(u_2.id = c_1.user_id)", 214 | "Shared Hit Blocks": 985, 215 | "Shared Read Blocks": 0, 216 | "Shared Dirtied Blocks": 0, 217 | "Shared Written Blocks": 0, 218 | "Local Hit Blocks": 0, 219 | "Local Read Blocks": 0, 220 | "Local Dirtied Blocks": 0, 221 | "Local Written Blocks": 0, 222 | "Temp Read Blocks": 0, 223 | "Temp Written Blocks": 0, 224 | "Plans": [ 225 | { 226 | "Node Type": "Seq Scan", 227 | "Parent Relationship": "Outer", 228 | "Parallel Aware": false, 229 | "Relation Name": "users", 230 | "Alias": "u_2", 231 | "Startup Cost": 0.00, 232 | "Total Cost": 1731.00, 233 | "Plan Rows": 100000, 234 | "Plan Width": 25, 235 | "Actual Startup Time": 0.016, 236 | "Actual Total Time": 0.017, 237 | "Actual Rows": 3, 238 | "Actual Loops": 1, 239 | "Shared Hit Blocks": 1, 240 | "Shared Read Blocks": 0, 241 | "Shared Dirtied Blocks": 0, 242 | "Shared Written Blocks": 0, 243 | "Local Hit Blocks": 0, 244 | "Local Read Blocks": 0, 245 | "Local Dirtied Blocks": 0, 246 | "Local Written Blocks": 0, 247 | "Temp Read Blocks": 0, 248 | "Temp Written Blocks": 0 249 | }, 250 | { 251 | "Node Type": "Hash", 252 | "Parent Relationship": "Inner", 253 | "Parallel Aware": false, 254 | "Startup Cost": 2234.00, 255 | "Total Cost": 2234.00, 256 | "Plan Rows": 50207, 257 | "Plan Width": 4, 258 | "Actual Startup Time": 252.611, 259 | "Actual Total Time": 252.611, 260 | "Actual Rows": 49998, 261 | "Actual Loops": 1, 262 | "Hash Buckets": 65536, 263 | "Original Hash Buckets": 65536, 264 | "Hash Batches": 1, 265 | "Original Hash Batches": 1, 266 | "Peak Memory Usage": 2270, 267 | "Shared Hit Blocks": 984, 268 | "Shared Read Blocks": 0, 269 | "Shared Dirtied Blocks": 0, 270 | "Shared Written Blocks": 0, 271 | "Local Hit Blocks": 0, 272 | "Local Read Blocks": 0, 273 | "Local Dirtied Blocks": 0, 274 | "Local Written Blocks": 0, 275 | "Temp Read Blocks": 0, 276 | "Temp Written Blocks": 0, 277 | "Plans": [ 278 | { 279 | "Node Type": "Seq Scan", 280 | "Parent Relationship": "Outer", 281 | "Parallel Aware": false, 282 | "Relation Name": "comments", 283 | "Alias": "c_1", 284 | "Startup Cost": 0.00, 285 | "Total Cost": 2234.00, 286 | "Plan Rows": 50207, 287 | "Plan Width": 4, 288 | "Actual Startup Time": 0.035, 289 | "Actual Total Time": 239.699, 290 | "Actual Rows": 49998, 291 | "Actual Loops": 1, 292 | "Filter": "((body)::text ~ '.*testing.*'::text)", 293 | "Rows Removed by Filter": 50002, 294 | "Shared Hit Blocks": 984, 295 | "Shared Read Blocks": 0, 296 | "Shared Dirtied Blocks": 0, 297 | "Shared Written Blocks": 0, 298 | "Local Hit Blocks": 0, 299 | "Local Read Blocks": 0, 300 | "Local Dirtied Blocks": 0, 301 | "Local Written Blocks": 0, 302 | "Temp Read Blocks": 0, 303 | "Temp Written Blocks": 0 304 | } 305 | ] 306 | } 307 | ] 308 | }, 309 | { 310 | "Node Type": "Hash Join", 311 | "Parent Relationship": "InitPlan", 312 | "Subplan Name": "CTE modularity_comments", 313 | "Parallel Aware": false, 314 | "Join Type": "Inner", 315 | "Startup Cost": 2545.59, 316 | "Total Cost": 5025.86, 317 | "Plan Rows": 24927, 318 | "Plan Width": 25, 319 | "Actual Startup Time": 279.072, 320 | "Actual Total Time": 279.073, 321 | "Actual Rows": 1, 322 | "Actual Loops": 1, 323 | "Inner Unique": false, 324 | "Hash Cond": "(u_3.id = c_2.user_id)", 325 | "Shared Hit Blocks": 985, 326 | "Shared Read Blocks": 0, 327 | "Shared Dirtied Blocks": 0, 328 | "Shared Written Blocks": 0, 329 | "Local Hit Blocks": 0, 330 | "Local Read Blocks": 0, 331 | "Local Dirtied Blocks": 0, 332 | "Local Written Blocks": 0, 333 | "Temp Read Blocks": 0, 334 | "Temp Written Blocks": 0, 335 | "Plans": [ 336 | { 337 | "Node Type": "Seq Scan", 338 | "Parent Relationship": "Outer", 339 | "Parallel Aware": false, 340 | "Relation Name": "users", 341 | "Alias": "u_3", 342 | "Startup Cost": 0.00, 343 | "Total Cost": 1731.00, 344 | "Plan Rows": 100000, 345 | "Plan Width": 25, 346 | "Actual Startup Time": 0.012, 347 | "Actual Total Time": 0.012, 348 | "Actual Rows": 1, 349 | "Actual Loops": 1, 350 | "Shared Hit Blocks": 1, 351 | "Shared Read Blocks": 0, 352 | "Shared Dirtied Blocks": 0, 353 | "Shared Written Blocks": 0, 354 | "Local Hit Blocks": 0, 355 | "Local Read Blocks": 0, 356 | "Local Dirtied Blocks": 0, 357 | "Local Written Blocks": 0, 358 | "Temp Read Blocks": 0, 359 | "Temp Written Blocks": 0 360 | }, 361 | { 362 | "Node Type": "Hash", 363 | "Parent Relationship": "Inner", 364 | "Parallel Aware": false, 365 | "Startup Cost": 2234.00, 366 | "Total Cost": 2234.00, 367 | "Plan Rows": 24927, 368 | "Plan Width": 4, 369 | "Actual Startup Time": 278.911, 370 | "Actual Total Time": 278.911, 371 | "Actual Rows": 25058, 372 | "Actual Loops": 1, 373 | "Hash Buckets": 32768, 374 | "Original Hash Buckets": 32768, 375 | "Hash Batches": 1, 376 | "Original Hash Batches": 1, 377 | "Peak Memory Usage": 1137, 378 | "Shared Hit Blocks": 984, 379 | "Shared Read Blocks": 0, 380 | "Shared Dirtied Blocks": 0, 381 | "Shared Written Blocks": 0, 382 | "Local Hit Blocks": 0, 383 | "Local Read Blocks": 0, 384 | "Local Dirtied Blocks": 0, 385 | "Local Written Blocks": 0, 386 | "Temp Read Blocks": 0, 387 | "Temp Written Blocks": 0, 388 | "Plans": [ 389 | { 390 | "Node Type": "Seq Scan", 391 | "Parent Relationship": "Outer", 392 | "Parallel Aware": false, 393 | "Relation Name": "comments", 394 | "Alias": "c_2", 395 | "Startup Cost": 0.00, 396 | "Total Cost": 2234.00, 397 | "Plan Rows": 24927, 398 | "Plan Width": 4, 399 | "Actual Startup Time": 0.025, 400 | "Actual Total Time": 271.456, 401 | "Actual Rows": 25058, 402 | "Actual Loops": 1, 403 | "Filter": "((body)::text ~ '.*modularity.*'::text)", 404 | "Rows Removed by Filter": 74942, 405 | "Shared Hit Blocks": 984, 406 | "Shared Read Blocks": 0, 407 | "Shared Dirtied Blocks": 0, 408 | "Shared Written Blocks": 0, 409 | "Local Hit Blocks": 0, 410 | "Local Read Blocks": 0, 411 | "Local Dirtied Blocks": 0, 412 | "Local Written Blocks": 0, 413 | "Temp Read Blocks": 0, 414 | "Temp Written Blocks": 0 415 | } 416 | ] 417 | } 418 | ] 419 | }, 420 | { 421 | "Node Type": "Index Scan", 422 | "Parent Relationship": "InitPlan", 423 | "Subplan Name": "CTE early_gmail_users", 424 | "Parallel Aware": false, 425 | "Scan Direction": "Forward", 426 | "Index Name": "users_pkey", 427 | "Relation Name": "users", 428 | "Alias": "users", 429 | "Startup Cost": 0.29, 430 | "Total Cost": 10.23, 431 | "Plan Rows": 25, 432 | "Plan Width": 4, 433 | "Actual Startup Time": 0.000, 434 | "Actual Total Time": 0.000, 435 | "Actual Rows": 0, 436 | "Actual Loops": 0, 437 | "Index Cond": "(id < 100)", 438 | "Rows Removed by Index Recheck": 0, 439 | "Filter": "((email)::text ~ '.*gmail.*'::text)", 440 | "Rows Removed by Filter": 0, 441 | "Shared Hit Blocks": 0, 442 | "Shared Read Blocks": 0, 443 | "Shared Dirtied Blocks": 0, 444 | "Shared Written Blocks": 0, 445 | "Local Hit Blocks": 0, 446 | "Local Read Blocks": 0, 447 | "Local Dirtied Blocks": 0, 448 | "Local Written Blocks": 0, 449 | "Temp Read Blocks": 0, 450 | "Temp Written Blocks": 0 451 | }, 452 | { 453 | "Node Type": "Index Scan", 454 | "Parent Relationship": "InitPlan", 455 | "Subplan Name": "CTE early_yahoo_users", 456 | "Parallel Aware": false, 457 | "Scan Direction": "Forward", 458 | "Index Name": "users_pkey", 459 | "Relation Name": "users", 460 | "Alias": "users_1", 461 | "Startup Cost": 0.29, 462 | "Total Cost": 10.23, 463 | "Plan Rows": 16, 464 | "Plan Width": 4, 465 | "Actual Startup Time": 0.000, 466 | "Actual Total Time": 0.000, 467 | "Actual Rows": 0, 468 | "Actual Loops": 0, 469 | "Index Cond": "(id < 100)", 470 | "Rows Removed by Index Recheck": 0, 471 | "Filter": "((email)::text ~ '.*yahoo.*'::text)", 472 | "Rows Removed by Filter": 0, 473 | "Shared Hit Blocks": 0, 474 | "Shared Read Blocks": 0, 475 | "Shared Dirtied Blocks": 0, 476 | "Shared Written Blocks": 0, 477 | "Local Hit Blocks": 0, 478 | "Local Read Blocks": 0, 479 | "Local Dirtied Blocks": 0, 480 | "Local Written Blocks": 0, 481 | "Temp Read Blocks": 0, 482 | "Temp Written Blocks": 0 483 | }, 484 | { 485 | "Node Type": "Index Scan", 486 | "Parent Relationship": "InitPlan", 487 | "Subplan Name": "CTE early_hotmail_users", 488 | "Parallel Aware": false, 489 | "Scan Direction": "Forward", 490 | "Index Name": "users_pkey", 491 | "Relation Name": "users", 492 | "Alias": "users_2", 493 | "Startup Cost": 0.29, 494 | "Total Cost": 10.23, 495 | "Plan Rows": 56, 496 | "Plan Width": 4, 497 | "Actual Startup Time": 0.000, 498 | "Actual Total Time": 0.000, 499 | "Actual Rows": 0, 500 | "Actual Loops": 0, 501 | "Index Cond": "(id < 100)", 502 | "Rows Removed by Index Recheck": 0, 503 | "Filter": "((email)::text ~ '.*hotmail.*'::text)", 504 | "Rows Removed by Filter": 0, 505 | "Shared Hit Blocks": 0, 506 | "Shared Read Blocks": 0, 507 | "Shared Dirtied Blocks": 0, 508 | "Shared Written Blocks": 0, 509 | "Local Hit Blocks": 0, 510 | "Local Read Blocks": 0, 511 | "Local Dirtied Blocks": 0, 512 | "Local Written Blocks": 0, 513 | "Temp Read Blocks": 0, 514 | "Temp Written Blocks": 0 515 | }, 516 | { 517 | "Node Type": "Nested Loop", 518 | "Parent Relationship": "Outer", 519 | "Parallel Aware": false, 520 | "Join Type": "Inner", 521 | "Startup Cost": 2031.99, 522 | "Total Cost": 2033.82, 523 | "Plan Rows": 1, 524 | "Plan Width": 25, 525 | "Actual Startup Time": 755.380, 526 | "Actual Total Time": 755.380, 527 | "Actual Rows": 0, 528 | "Actual Loops": 1, 529 | "Inner Unique": false, 530 | "Join Filter": "(eyu.id = u.id)", 531 | "Rows Removed by Join Filter": 0, 532 | "Shared Hit Blocks": 2957, 533 | "Shared Read Blocks": 0, 534 | "Shared Dirtied Blocks": 0, 535 | "Shared Written Blocks": 0, 536 | "Local Hit Blocks": 0, 537 | "Local Read Blocks": 0, 538 | "Local Dirtied Blocks": 0, 539 | "Local Written Blocks": 0, 540 | "Temp Read Blocks": 0, 541 | "Temp Written Blocks": 0, 542 | "Plans": [ 543 | { 544 | "Node Type": "Merge Join", 545 | "Parent Relationship": "Outer", 546 | "Parallel Aware": false, 547 | "Join Type": "Inner", 548 | "Startup Cost": 2031.47, 549 | "Total Cost": 2031.61, 550 | "Plan Rows": 1, 551 | "Plan Width": 53, 552 | "Actual Startup Time": 755.379, 553 | "Actual Total Time": 755.380, 554 | "Actual Rows": 0, 555 | "Actual Loops": 1, 556 | "Inner Unique": false, 557 | "Merge Cond": "(u.id = egu.id)", 558 | "Shared Hit Blocks": 2957, 559 | "Shared Read Blocks": 0, 560 | "Shared Dirtied Blocks": 0, 561 | "Shared Written Blocks": 0, 562 | "Local Hit Blocks": 0, 563 | "Local Read Blocks": 0, 564 | "Local Dirtied Blocks": 0, 565 | "Local Written Blocks": 0, 566 | "Temp Read Blocks": 0, 567 | "Temp Written Blocks": 0, 568 | "Plans": [ 569 | { 570 | "Node Type": "Sort", 571 | "Parent Relationship": "Outer", 572 | "Parallel Aware": false, 573 | "Startup Cost": 2030.39, 574 | "Total Cost": 2030.39, 575 | "Plan Rows": 1, 576 | "Plan Width": 49, 577 | "Actual Startup Time": 755.378, 578 | "Actual Total Time": 755.379, 579 | "Actual Rows": 0, 580 | "Actual Loops": 1, 581 | "Sort Key": ["u.id"], 582 | "Sort Method": "quicksort", 583 | "Sort Space Used": 25, 584 | "Sort Space Type": "Memory", 585 | "Shared Hit Blocks": 2957, 586 | "Shared Read Blocks": 0, 587 | "Shared Dirtied Blocks": 0, 588 | "Shared Written Blocks": 0, 589 | "Local Hit Blocks": 0, 590 | "Local Read Blocks": 0, 591 | "Local Dirtied Blocks": 0, 592 | "Local Written Blocks": 0, 593 | "Temp Read Blocks": 0, 594 | "Temp Written Blocks": 0, 595 | "Plans": [ 596 | { 597 | "Node Type": "Hash Join", 598 | "Parent Relationship": "Outer", 599 | "Parallel Aware": false, 600 | "Join Type": "Inner", 601 | "Startup Cost": 837.95, 602 | "Total Cost": 2030.38, 603 | "Plan Rows": 1, 604 | "Plan Width": 49, 605 | "Actual Startup Time": 755.357, 606 | "Actual Total Time": 755.357, 607 | "Actual Rows": 0, 608 | "Actual Loops": 1, 609 | "Inner Unique": false, 610 | "Hash Cond": "(tc.user_id = u.id)", 611 | "Shared Hit Blocks": 2957, 612 | "Shared Read Blocks": 0, 613 | "Shared Dirtied Blocks": 0, 614 | "Shared Written Blocks": 0, 615 | "Local Hit Blocks": 0, 616 | "Local Read Blocks": 0, 617 | "Local Dirtied Blocks": 0, 618 | "Local Written Blocks": 0, 619 | "Temp Read Blocks": 0, 620 | "Temp Written Blocks": 0, 621 | "Plans": [ 622 | { 623 | "Node Type": "CTE Scan", 624 | "Parent Relationship": "Outer", 625 | "Parallel Aware": false, 626 | "CTE Name": "testing_comments", 627 | "Alias": "tc", 628 | "Startup Cost": 0.00, 629 | "Total Cost": 1004.14, 630 | "Plan Rows": 50207, 631 | "Plan Width": 4, 632 | "Actual Startup Time": 252.951, 633 | "Actual Total Time": 252.951, 634 | "Actual Rows": 1, 635 | "Actual Loops": 1, 636 | "Shared Hit Blocks": 985, 637 | "Shared Read Blocks": 0, 638 | "Shared Dirtied Blocks": 0, 639 | "Shared Written Blocks": 0, 640 | "Local Hit Blocks": 0, 641 | "Local Read Blocks": 0, 642 | "Local Dirtied Blocks": 0, 643 | "Local Written Blocks": 0, 644 | "Temp Read Blocks": 0, 645 | "Temp Written Blocks": 0 646 | }, 647 | { 648 | "Node Type": "Hash", 649 | "Parent Relationship": "Inner", 650 | "Parallel Aware": false, 651 | "Startup Cost": 837.94, 652 | "Total Cost": 837.94, 653 | "Plan Rows": 1, 654 | "Plan Width": 45, 655 | "Actual Startup Time": 502.388, 656 | "Actual Total Time": 502.388, 657 | "Actual Rows": 0, 658 | "Actual Loops": 1, 659 | "Hash Buckets": 1024, 660 | "Original Hash Buckets": 1024, 661 | "Hash Batches": 1, 662 | "Original Hash Batches": 1, 663 | "Peak Memory Usage": 8, 664 | "Shared Hit Blocks": 1972, 665 | "Shared Read Blocks": 0, 666 | "Shared Dirtied Blocks": 0, 667 | "Shared Written Blocks": 0, 668 | "Local Hit Blocks": 0, 669 | "Local Read Blocks": 0, 670 | "Local Dirtied Blocks": 0, 671 | "Local Written Blocks": 0, 672 | "Temp Read Blocks": 0, 673 | "Temp Written Blocks": 0, 674 | "Plans": [ 675 | { 676 | "Node Type": "Hash Join", 677 | "Parent Relationship": "Outer", 678 | "Parallel Aware": false, 679 | "Join Type": "Inner", 680 | "Startup Cost": 245.91, 681 | "Total Cost": 837.94, 682 | "Plan Rows": 1, 683 | "Plan Width": 45, 684 | "Actual Startup Time": 502.387, 685 | "Actual Total Time": 502.387, 686 | "Actual Rows": 0, 687 | "Actual Loops": 1, 688 | "Inner Unique": false, 689 | "Hash Cond": "(mc.user_id = u.id)", 690 | "Shared Hit Blocks": 1972, 691 | "Shared Read Blocks": 0, 692 | "Shared Dirtied Blocks": 0, 693 | "Shared Written Blocks": 0, 694 | "Local Hit Blocks": 0, 695 | "Local Read Blocks": 0, 696 | "Local Dirtied Blocks": 0, 697 | "Local Written Blocks": 0, 698 | "Temp Read Blocks": 0, 699 | "Temp Written Blocks": 0, 700 | "Plans": [ 701 | { 702 | "Node Type": "CTE Scan", 703 | "Parent Relationship": "Outer", 704 | "Parallel Aware": false, 705 | "CTE Name": "modularity_comments", 706 | "Alias": "mc", 707 | "Startup Cost": 0.00, 708 | "Total Cost": 498.54, 709 | "Plan Rows": 24927, 710 | "Plan Width": 4, 711 | "Actual Startup Time": 279.075, 712 | "Actual Total Time": 279.075, 713 | "Actual Rows": 1, 714 | "Actual Loops": 1, 715 | "Shared Hit Blocks": 985, 716 | "Shared Read Blocks": 0, 717 | "Shared Dirtied Blocks": 0, 718 | "Shared Written Blocks": 0, 719 | "Local Hit Blocks": 0, 720 | "Local Read Blocks": 0, 721 | "Local Dirtied Blocks": 0, 722 | "Local Written Blocks": 0, 723 | "Temp Read Blocks": 0, 724 | "Temp Written Blocks": 0 725 | }, 726 | { 727 | "Node Type": "Hash", 728 | "Parent Relationship": "Inner", 729 | "Parallel Aware": false, 730 | "Startup Cost": 245.90, 731 | "Total Cost": 245.90, 732 | "Plan Rows": 1, 733 | "Plan Width": 41, 734 | "Actual Startup Time": 223.292, 735 | "Actual Total Time": 223.292, 736 | "Actual Rows": 0, 737 | "Actual Loops": 1, 738 | "Hash Buckets": 1024, 739 | "Original Hash Buckets": 1024, 740 | "Hash Batches": 1, 741 | "Original Hash Batches": 1, 742 | "Peak Memory Usage": 8, 743 | "Shared Hit Blocks": 987, 744 | "Shared Read Blocks": 0, 745 | "Shared Dirtied Blocks": 0, 746 | "Shared Written Blocks": 0, 747 | "Local Hit Blocks": 0, 748 | "Local Read Blocks": 0, 749 | "Local Dirtied Blocks": 0, 750 | "Local Written Blocks": 0, 751 | "Temp Read Blocks": 0, 752 | "Temp Written Blocks": 0, 753 | "Plans": [ 754 | { 755 | "Node Type": "Hash Join", 756 | "Parent Relationship": "Outer", 757 | "Parallel Aware": false, 758 | "Join Type": "Inner", 759 | "Startup Cost": 127.83, 760 | "Total Cost": 245.90, 761 | "Plan Rows": 1, 762 | "Plan Width": 41, 763 | "Actual Startup Time": 223.291, 764 | "Actual Total Time": 223.291, 765 | "Actual Rows": 0, 766 | "Actual Loops": 1, 767 | "Inner Unique": false, 768 | "Hash Cond": "(sp.user_id = u.id)", 769 | "Shared Hit Blocks": 987, 770 | "Shared Read Blocks": 0, 771 | "Shared Dirtied Blocks": 0, 772 | "Shared Written Blocks": 0, 773 | "Local Hit Blocks": 0, 774 | "Local Read Blocks": 0, 775 | "Local Dirtied Blocks": 0, 776 | "Local Written Blocks": 0, 777 | "Temp Read Blocks": 0, 778 | "Temp Written Blocks": 0, 779 | "Plans": [ 780 | { 781 | "Node Type": "CTE Scan", 782 | "Parent Relationship": "Outer", 783 | "Parallel Aware": false, 784 | "CTE Name": "sql_posts", 785 | "Alias": "sp", 786 | "Startup Cost": 0.00, 787 | "Total Cost": 99.42, 788 | "Plan Rows": 4971, 789 | "Plan Width": 4, 790 | "Actual Startup Time": 0.025, 791 | "Actual Total Time": 0.025, 792 | "Actual Rows": 1, 793 | "Actual Loops": 1, 794 | "Shared Hit Blocks": 1, 795 | "Shared Read Blocks": 0, 796 | "Shared Dirtied Blocks": 0, 797 | "Shared Written Blocks": 0, 798 | "Local Hit Blocks": 0, 799 | "Local Read Blocks": 0, 800 | "Local Dirtied Blocks": 0, 801 | "Local Written Blocks": 0, 802 | "Temp Read Blocks": 0, 803 | "Temp Written Blocks": 0 804 | }, 805 | { 806 | "Node Type": "Hash", 807 | "Parent Relationship": "Inner", 808 | "Parallel Aware": false, 809 | "Startup Cost": 127.81, 810 | "Total Cost": 127.81, 811 | "Plan Rows": 1, 812 | "Plan Width": 37, 813 | "Actual Startup Time": 223.252, 814 | "Actual Total Time": 223.252, 815 | "Actual Rows": 0, 816 | "Actual Loops": 1, 817 | "Hash Buckets": 1024, 818 | "Original Hash Buckets": 1024, 819 | "Hash Batches": 1, 820 | "Original Hash Batches": 1, 821 | "Peak Memory Usage": 8, 822 | "Shared Hit Blocks": 986, 823 | "Shared Read Blocks": 0, 824 | "Shared Dirtied Blocks": 0, 825 | "Shared Written Blocks": 0, 826 | "Local Hit Blocks": 0, 827 | "Local Read Blocks": 0, 828 | "Local Dirtied Blocks": 0, 829 | "Local Written Blocks": 0, 830 | "Temp Read Blocks": 0, 831 | "Temp Written Blocks": 0, 832 | "Plans": [ 833 | { 834 | "Node Type": "Hash Join", 835 | "Parent Relationship": "Outer", 836 | "Parallel Aware": false, 837 | "Join Type": "Inner", 838 | "Startup Cost": 67.29, 839 | "Total Cost": 127.81, 840 | "Plan Rows": 1, 841 | "Plan Width": 37, 842 | "Actual Startup Time": 223.252, 843 | "Actual Total Time": 223.252, 844 | "Actual Rows": 0, 845 | "Actual Loops": 1, 846 | "Inner Unique": false, 847 | "Hash Cond": "(dp.user_id = u.id)", 848 | "Shared Hit Blocks": 986, 849 | "Shared Read Blocks": 0, 850 | "Shared Dirtied Blocks": 0, 851 | "Shared Written Blocks": 0, 852 | "Local Hit Blocks": 0, 853 | "Local Read Blocks": 0, 854 | "Local Dirtied Blocks": 0, 855 | "Local Written Blocks": 0, 856 | "Temp Read Blocks": 0, 857 | "Temp Written Blocks": 0, 858 | "Plans": [ 859 | { 860 | "Node Type": "CTE Scan", 861 | "Parent Relationship": "Outer", 862 | "Parallel Aware": false, 863 | "CTE Name": "database_posts", 864 | "Alias": "dp", 865 | "Startup Cost": 0.00, 866 | "Total Cost": 50.96, 867 | "Plan Rows": 2548, 868 | "Plan Width": 4, 869 | "Actual Startup Time": 0.011, 870 | "Actual Total Time": 0.011, 871 | "Actual Rows": 1, 872 | "Actual Loops": 1, 873 | "Shared Hit Blocks": 1, 874 | "Shared Read Blocks": 0, 875 | "Shared Dirtied Blocks": 0, 876 | "Shared Written Blocks": 0, 877 | "Local Hit Blocks": 0, 878 | "Local Read Blocks": 0, 879 | "Local Dirtied Blocks": 0, 880 | "Local Written Blocks": 0, 881 | "Temp Read Blocks": 0, 882 | "Temp Written Blocks": 0 883 | }, 884 | { 885 | "Node Type": "Hash", 886 | "Parent Relationship": "Inner", 887 | "Parallel Aware": false, 888 | "Startup Cost": 67.28, 889 | "Total Cost": 67.28, 890 | "Plan Rows": 1, 891 | "Plan Width": 33, 892 | "Actual Startup Time": 223.214, 893 | "Actual Total Time": 223.214, 894 | "Actual Rows": 0, 895 | "Actual Loops": 1, 896 | "Hash Buckets": 1024, 897 | "Original Hash Buckets": 1024, 898 | "Hash Batches": 1, 899 | "Original Hash Batches": 1, 900 | "Peak Memory Usage": 8, 901 | "Shared Hit Blocks": 985, 902 | "Shared Read Blocks": 0, 903 | "Shared Dirtied Blocks": 0, 904 | "Shared Written Blocks": 0, 905 | "Local Hit Blocks": 0, 906 | "Local Read Blocks": 0, 907 | "Local Dirtied Blocks": 0, 908 | "Local Written Blocks": 0, 909 | "Temp Read Blocks": 0, 910 | "Temp Written Blocks": 0, 911 | "Plans": [ 912 | { 913 | "Node Type": "Hash Join", 914 | "Parent Relationship": "Outer", 915 | "Parallel Aware": false, 916 | "Join Type": "Inner", 917 | "Startup Cost": 8.34, 918 | "Total Cost": 67.28, 919 | "Plan Rows": 1, 920 | "Plan Width": 33, 921 | "Actual Startup Time": 223.213, 922 | "Actual Total Time": 223.214, 923 | "Actual Rows": 0, 924 | "Actual Loops": 1, 925 | "Inner Unique": false, 926 | "Hash Cond": "(pp.user_id = u.id)", 927 | "Shared Hit Blocks": 985, 928 | "Shared Read Blocks": 0, 929 | "Shared Dirtied Blocks": 0, 930 | "Shared Written Blocks": 0, 931 | "Local Hit Blocks": 0, 932 | "Local Read Blocks": 0, 933 | "Local Dirtied Blocks": 0, 934 | "Local Written Blocks": 0, 935 | "Temp Read Blocks": 0, 936 | "Temp Written Blocks": 0, 937 | "Plans": [ 938 | { 939 | "Node Type": "CTE Scan", 940 | "Parent Relationship": "Outer", 941 | "Parallel Aware": false, 942 | "CTE Name": "postgres_posts", 943 | "Alias": "pp", 944 | "Startup Cost": 0.00, 945 | "Total Cost": 49.62, 946 | "Plan Rows": 2481, 947 | "Plan Width": 4, 948 | "Actual Startup Time": 0.035, 949 | "Actual Total Time": 0.035, 950 | "Actual Rows": 1, 951 | "Actual Loops": 1, 952 | "Shared Hit Blocks": 1, 953 | "Shared Read Blocks": 0, 954 | "Shared Dirtied Blocks": 0, 955 | "Shared Written Blocks": 0, 956 | "Local Hit Blocks": 0, 957 | "Local Read Blocks": 0, 958 | "Local Dirtied Blocks": 0, 959 | "Local Written Blocks": 0, 960 | "Temp Read Blocks": 0, 961 | "Temp Written Blocks": 0 962 | }, 963 | { 964 | "Node Type": "Hash", 965 | "Parent Relationship": "Inner", 966 | "Parallel Aware": false, 967 | "Startup Cost": 8.33, 968 | "Total Cost": 8.33, 969 | "Plan Rows": 1, 970 | "Plan Width": 29, 971 | "Actual Startup Time": 223.167, 972 | "Actual Total Time": 223.167, 973 | "Actual Rows": 0, 974 | "Actual Loops": 1, 975 | "Hash Buckets": 1024, 976 | "Original Hash Buckets": 1024, 977 | "Hash Batches": 1, 978 | "Original Hash Batches": 1, 979 | "Peak Memory Usage": 8, 980 | "Shared Hit Blocks": 984, 981 | "Shared Read Blocks": 0, 982 | "Shared Dirtied Blocks": 0, 983 | "Shared Written Blocks": 0, 984 | "Local Hit Blocks": 0, 985 | "Local Read Blocks": 0, 986 | "Local Dirtied Blocks": 0, 987 | "Local Written Blocks": 0, 988 | "Temp Read Blocks": 0, 989 | "Temp Written Blocks": 0, 990 | "Plans": [ 991 | { 992 | "Node Type": "Nested Loop", 993 | "Parent Relationship": "Outer", 994 | "Parallel Aware": false, 995 | "Join Type": "Inner", 996 | "Startup Cost": 0.29, 997 | "Total Cost": 8.33, 998 | "Plan Rows": 1, 999 | "Plan Width": 29, 1000 | "Actual Startup Time": 223.166, 1001 | "Actual Total Time": 223.166, 1002 | "Actual Rows": 0, 1003 | "Actual Loops": 1, 1004 | "Inner Unique": true, 1005 | "Shared Hit Blocks": 984, 1006 | "Shared Read Blocks": 0, 1007 | "Shared Dirtied Blocks": 0, 1008 | "Shared Written Blocks": 0, 1009 | "Local Hit Blocks": 0, 1010 | "Local Read Blocks": 0, 1011 | "Local Dirtied Blocks": 0, 1012 | "Local Written Blocks": 0, 1013 | "Temp Read Blocks": 0, 1014 | "Temp Written Blocks": 0, 1015 | "Plans": [ 1016 | { 1017 | "Node Type": "CTE Scan", 1018 | "Parent Relationship": "Outer", 1019 | "Parallel Aware": false, 1020 | "CTE Name": "performance_comments", 1021 | "Alias": "pc", 1022 | "Startup Cost": 0.00, 1023 | "Total Cost": 0.02, 1024 | "Plan Rows": 1, 1025 | "Plan Width": 4, 1026 | "Actual Startup Time": 223.166, 1027 | "Actual Total Time": 223.166, 1028 | "Actual Rows": 0, 1029 | "Actual Loops": 1, 1030 | "Shared Hit Blocks": 984, 1031 | "Shared Read Blocks": 0, 1032 | "Shared Dirtied Blocks": 0, 1033 | "Shared Written Blocks": 0, 1034 | "Local Hit Blocks": 0, 1035 | "Local Read Blocks": 0, 1036 | "Local Dirtied Blocks": 0, 1037 | "Local Written Blocks": 0, 1038 | "Temp Read Blocks": 0, 1039 | "Temp Written Blocks": 0 1040 | }, 1041 | { 1042 | "Node Type": "Index Scan", 1043 | "Parent Relationship": "Inner", 1044 | "Parallel Aware": false, 1045 | "Scan Direction": "Forward", 1046 | "Index Name": "users_pkey", 1047 | "Relation Name": "users", 1048 | "Alias": "u", 1049 | "Startup Cost": 0.29, 1050 | "Total Cost": 8.31, 1051 | "Plan Rows": 1, 1052 | "Plan Width": 25, 1053 | "Actual Startup Time": 0.000, 1054 | "Actual Total Time": 0.000, 1055 | "Actual Rows": 0, 1056 | "Actual Loops": 0, 1057 | "Index Cond": "(id = pc.user_id)", 1058 | "Rows Removed by Index Recheck": 0, 1059 | "Shared Hit Blocks": 0, 1060 | "Shared Read Blocks": 0, 1061 | "Shared Dirtied Blocks": 0, 1062 | "Shared Written Blocks": 0, 1063 | "Local Hit Blocks": 0, 1064 | "Local Read Blocks": 0, 1065 | "Local Dirtied Blocks": 0, 1066 | "Local Written Blocks": 0, 1067 | "Temp Read Blocks": 0, 1068 | "Temp Written Blocks": 0 1069 | } 1070 | ] 1071 | } 1072 | ] 1073 | } 1074 | ] 1075 | } 1076 | ] 1077 | } 1078 | ] 1079 | } 1080 | ] 1081 | } 1082 | ] 1083 | } 1084 | ] 1085 | } 1086 | ] 1087 | } 1088 | ] 1089 | } 1090 | ] 1091 | } 1092 | ] 1093 | }, 1094 | { 1095 | "Node Type": "Sort", 1096 | "Parent Relationship": "Inner", 1097 | "Parallel Aware": false, 1098 | "Startup Cost": 1.08, 1099 | "Total Cost": 1.14, 1100 | "Plan Rows": 25, 1101 | "Plan Width": 4, 1102 | "Actual Startup Time": 0.000, 1103 | "Actual Total Time": 0.000, 1104 | "Actual Rows": 0, 1105 | "Actual Loops": 0, 1106 | "Sort Key": ["egu.id"], 1107 | "Shared Hit Blocks": 0, 1108 | "Shared Read Blocks": 0, 1109 | "Shared Dirtied Blocks": 0, 1110 | "Shared Written Blocks": 0, 1111 | "Local Hit Blocks": 0, 1112 | "Local Read Blocks": 0, 1113 | "Local Dirtied Blocks": 0, 1114 | "Local Written Blocks": 0, 1115 | "Temp Read Blocks": 0, 1116 | "Temp Written Blocks": 0, 1117 | "Plans": [ 1118 | { 1119 | "Node Type": "CTE Scan", 1120 | "Parent Relationship": "Outer", 1121 | "Parallel Aware": false, 1122 | "CTE Name": "early_gmail_users", 1123 | "Alias": "egu", 1124 | "Startup Cost": 0.00, 1125 | "Total Cost": 0.50, 1126 | "Plan Rows": 25, 1127 | "Plan Width": 4, 1128 | "Actual Startup Time": 0.000, 1129 | "Actual Total Time": 0.000, 1130 | "Actual Rows": 0, 1131 | "Actual Loops": 0, 1132 | "Shared Hit Blocks": 0, 1133 | "Shared Read Blocks": 0, 1134 | "Shared Dirtied Blocks": 0, 1135 | "Shared Written Blocks": 0, 1136 | "Local Hit Blocks": 0, 1137 | "Local Read Blocks": 0, 1138 | "Local Dirtied Blocks": 0, 1139 | "Local Written Blocks": 0, 1140 | "Temp Read Blocks": 0, 1141 | "Temp Written Blocks": 0 1142 | } 1143 | ] 1144 | } 1145 | ] 1146 | }, 1147 | { 1148 | "Node Type": "Hash Join", 1149 | "Parent Relationship": "Inner", 1150 | "Parallel Aware": false, 1151 | "Join Type": "Inner", 1152 | "Startup Cost": 0.52, 1153 | "Total Cost": 2.01, 1154 | "Plan Rows": 16, 1155 | "Plan Width": 8, 1156 | "Actual Startup Time": 0.000, 1157 | "Actual Total Time": 0.000, 1158 | "Actual Rows": 0, 1159 | "Actual Loops": 0, 1160 | "Inner Unique": false, 1161 | "Hash Cond": "(ehu.id = eyu.id)", 1162 | "Shared Hit Blocks": 0, 1163 | "Shared Read Blocks": 0, 1164 | "Shared Dirtied Blocks": 0, 1165 | "Shared Written Blocks": 0, 1166 | "Local Hit Blocks": 0, 1167 | "Local Read Blocks": 0, 1168 | "Local Dirtied Blocks": 0, 1169 | "Local Written Blocks": 0, 1170 | "Temp Read Blocks": 0, 1171 | "Temp Written Blocks": 0, 1172 | "Plans": [ 1173 | { 1174 | "Node Type": "CTE Scan", 1175 | "Parent Relationship": "Outer", 1176 | "Parallel Aware": false, 1177 | "CTE Name": "early_hotmail_users", 1178 | "Alias": "ehu", 1179 | "Startup Cost": 0.00, 1180 | "Total Cost": 1.12, 1181 | "Plan Rows": 56, 1182 | "Plan Width": 4, 1183 | "Actual Startup Time": 0.000, 1184 | "Actual Total Time": 0.000, 1185 | "Actual Rows": 0, 1186 | "Actual Loops": 0, 1187 | "Shared Hit Blocks": 0, 1188 | "Shared Read Blocks": 0, 1189 | "Shared Dirtied Blocks": 0, 1190 | "Shared Written Blocks": 0, 1191 | "Local Hit Blocks": 0, 1192 | "Local Read Blocks": 0, 1193 | "Local Dirtied Blocks": 0, 1194 | "Local Written Blocks": 0, 1195 | "Temp Read Blocks": 0, 1196 | "Temp Written Blocks": 0 1197 | }, 1198 | { 1199 | "Node Type": "Hash", 1200 | "Parent Relationship": "Inner", 1201 | "Parallel Aware": false, 1202 | "Startup Cost": 0.32, 1203 | "Total Cost": 0.32, 1204 | "Plan Rows": 16, 1205 | "Plan Width": 4, 1206 | "Actual Startup Time": 0.000, 1207 | "Actual Total Time": 0.000, 1208 | "Actual Rows": 0, 1209 | "Actual Loops": 0, 1210 | "Shared Hit Blocks": 0, 1211 | "Shared Read Blocks": 0, 1212 | "Shared Dirtied Blocks": 0, 1213 | "Shared Written Blocks": 0, 1214 | "Local Hit Blocks": 0, 1215 | "Local Read Blocks": 0, 1216 | "Local Dirtied Blocks": 0, 1217 | "Local Written Blocks": 0, 1218 | "Temp Read Blocks": 0, 1219 | "Temp Written Blocks": 0, 1220 | "Plans": [ 1221 | { 1222 | "Node Type": "CTE Scan", 1223 | "Parent Relationship": "Outer", 1224 | "Parallel Aware": false, 1225 | "CTE Name": "early_yahoo_users", 1226 | "Alias": "eyu", 1227 | "Startup Cost": 0.00, 1228 | "Total Cost": 0.32, 1229 | "Plan Rows": 16, 1230 | "Plan Width": 4, 1231 | "Actual Startup Time": 0.000, 1232 | "Actual Total Time": 0.000, 1233 | "Actual Rows": 0, 1234 | "Actual Loops": 0, 1235 | "Shared Hit Blocks": 0, 1236 | "Shared Read Blocks": 0, 1237 | "Shared Dirtied Blocks": 0, 1238 | "Shared Written Blocks": 0, 1239 | "Local Hit Blocks": 0, 1240 | "Local Read Blocks": 0, 1241 | "Local Dirtied Blocks": 0, 1242 | "Local Written Blocks": 0, 1243 | "Temp Read Blocks": 0, 1244 | "Temp Written Blocks": 0 1245 | } 1246 | ] 1247 | } 1248 | ] 1249 | } 1250 | ] 1251 | } 1252 | ] 1253 | }, 1254 | "Planning Time": 20.603, 1255 | "Triggers": [ 1256 | ], 1257 | "Execution Time": 756.376 1258 | } 1259 | ] 1260 | -------------------------------------------------------------------------------- /docs/cte_flamegraph.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 56 | 57 | pg_flame 58 | 59 | 60 | 61 | 62 | 63 |
64 |
65 | 77 | 80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 | 88 | 89 | 90 | 91 | 92 | 149 | 150 | 151 | --------------------------------------------------------------------------------