Skip to content

Commit

Permalink
sql: add index recommendation to EXPLAIN
Browse files Browse the repository at this point in the history
Previously, the EXPLAIN output only showed the query plan. Since users
often use EXPLAIN to see why a query is poorly performing, it would
be useful for them to also see index recommendations to make the query
faster. In this commit, index recommendations are added to the bottom of
the EXPLAIN output. See the indexrec package under `pkg/sql/opt/indexrec`
to understand how index recommendations are generated.

Release note (sql change): The output of the EXPLAIN SQL statement has changed.
Below the plan, we now output index recommendations for the SQL statement being
"EXPLAIN-ed", if there are any. These index recommendations are indexes the
user could add or indexes they could replace to make the given query faster.
  • Loading branch information
Neha George committed Dec 1, 2021
1 parent bf503ad commit 5bea547
Show file tree
Hide file tree
Showing 57 changed files with 1,897 additions and 64 deletions.
2 changes: 1 addition & 1 deletion pkg/ccl/logictestccl/testdata/logic_test/as_of
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ SELECT * FROM t AS OF SYSTEM TIME with_max_staleness('1ms') WHERE j = 2
query T
EXPLAIN (OPT, MEMO) SELECT * FROM t AS OF SYSTEM TIME with_max_staleness('1ms') WHERE j = 2 AND i = 1
----
memo (optimized, ~7KB, required=[presentation: info:6])
memo (optimized, ~5KB, required=[presentation: info:6])
├── G1: (explain G2 [presentation: i:1,j:2,k:3])
│ └── [presentation: info:6]
│ ├── best: (explain G2="[presentation: i:1,j:2,k:3]" [presentation: i:1,j:2,k:3])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ select
│ ├── [/3/3/1 - /3/3/9]
│ └── [/3/4/1 - ]
└── filters
├── (c % 2) = 1
└── (c > 0) AND (c < 10)
├── (c > 0) AND (c < 10)
└── (c % 2) = 1

# Perhaps an unintuitive example. The partition constraints don't really help
# constrain the index. None of the spans created by the partitioning are constrained
Expand Down
22 changes: 22 additions & 0 deletions pkg/ccl/logictestccl/testdata/logic_test/partitioning_implicit
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,12 @@ vectorized: true
└── • scan buffer
label: buffer 1
·
index recommendations: 2
1. type: index creation
SQL command: CREATE INDEX ON t (pk);
2. type: index creation
SQL command: CREATE INDEX ON t (c);

statement ok
INSERT INTO fk_using_implicit_columns_against_t VALUES (1, 1, 4)
Expand Down Expand Up @@ -799,6 +805,14 @@ vectorized: true
└── • scan buffer
label: buffer 1
·
index recommendations: 3
1. type: index creation
SQL command: CREATE INDEX ON t (pk);
2. type: index creation
SQL command: CREATE INDEX ON t (b);
3. type: index creation
SQL command: CREATE INDEX ON t (c, d);

statement ok
INSERT INTO t VALUES (1, 1, 1, 1, 1, 1, 1), (2, 2, 2, 2, 2, 2, 2)
Expand Down Expand Up @@ -884,6 +898,14 @@ vectorized: true
└── • scan buffer
label: buffer 1
·
index recommendations: 3
1. type: index creation
SQL command: CREATE INDEX ON t (pk) STORING (pk2, a, b, c, d);
2. type: index creation
SQL command: CREATE INDEX ON t (b);
3. type: index creation
SQL command: CREATE INDEX ON t (c, d);

# One row already exists, one row is new.
statement ok
Expand Down
2 changes: 2 additions & 0 deletions pkg/sql/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,9 @@ go_library(
"//pkg/sql/opt/exec",
"//pkg/sql/opt/exec/execbuilder",
"//pkg/sql/opt/exec/explain",
"//pkg/sql/opt/indexrec",
"//pkg/sql/opt/memo",
"//pkg/sql/opt/norm",
"//pkg/sql/opt/optbuilder",
"//pkg/sql/opt/xform",
"//pkg/sql/optionalnodeliveness",
Expand Down
6 changes: 6 additions & 0 deletions pkg/sql/explain_plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,12 @@ func (e *explainPlanNode) startExec(params runParams) error {
}
}
}
// Add index recommendations to output, if they exist.
if params.p.instrumentation.indexRecommendations != nil {
// First add empty row.
rows = append(rows, "")
rows = append(rows, params.p.instrumentation.indexRecommendations...)
}
v := params.p.newContainerValuesNode(colinfo.ExplainPlanColumns, 0)
datums := make([]tree.DString, len(rows))
for i, row := range rows {
Expand Down
4 changes: 4 additions & 0 deletions pkg/sql/instrumentation.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ type instrumentationHelper struct {

// costEstimate is the cost of the query as estimated by the optimizer.
costEstimate float64

// indexRecommendations is a string slice containing index recommendations for
// the planned statement. This is only set for EXPLAIN statements.
indexRecommendations []string
}

// outputMode indicates how the statement output needs to be populated (for
Expand Down
5 changes: 5 additions & 0 deletions pkg/sql/opt/cat/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ package cat
import (
"time"

"github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb"
"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
)

Expand Down Expand Up @@ -136,6 +137,10 @@ type Table interface {

// Zone returns a table's zone.
Zone() Zone

// LookupColumnOrdinal returns the ordinal of the column with the given ID. A
// cache makes the lookup O(1).
LookupColumnOrdinal(colID descpb.ColumnID) (int, error)
}

// CheckConstraint contains the SQL text and the validity status for a check
Expand Down
114 changes: 98 additions & 16 deletions pkg/sql/opt/exec/execbuilder/testdata/aggregate
Original file line number Diff line number Diff line change
Expand Up @@ -676,6 +676,10 @@ vectorized: true
table: xyz@zyx
spans: /7/!NULL-/7.000000000000001
limit: 1
·
index recommendations: 1
1. type: index creation
SQL command: CREATE INDEX ON xyz (z) STORING (y);

query T
EXPLAIN (TYPES) SELECT max(y) FROM xyz WHERE z = 7
Expand All @@ -697,6 +701,10 @@ vectorized: true
table: xyz@zyx
spans: /7/!NULL-/7.000000000000001
limit: 1
·
index recommendations: 1
1. type: index creation
SQL command: CREATE INDEX ON xyz (z) STORING (y);

query T
EXPLAIN (TYPES) SELECT min(x) FROM xyz WHERE (y, z) = (2, 3.0)
Expand All @@ -718,6 +726,10 @@ vectorized: true
table: xyz@zyx
spans: /3/2-/3/3
limit: 1
·
index recommendations: 1
1. type: index creation
SQL command: CREATE INDEX ON xyz (y, z);

statement ok
SET tracing = on,kv,results; SELECT min(x) FROM xyz WHERE (y, z) = (2, 3.0); SET tracing = off
Expand Down Expand Up @@ -750,6 +762,10 @@ vectorized: true
table: xyz@zyx
spans: /3/2-/3/3
limit: 1
·
index recommendations: 1
1. type: index creation
SQL command: CREATE INDEX ON xyz (z, y);

# MULTIPLE MIN/MAX

Expand Down Expand Up @@ -935,22 +951,26 @@ vectorized: true
│ spans: (/NULL - ]
└── • subquery
│ id: @S2
│ original sql: <unknown>
│ exec mode: one row
└── • group (scalar)
└── • limit
│ count: 1
└── • filter
│ filter: y > 0
└── • scan
missing stats
table: xyz@xy
spans: FULL SCAN
│ id: @S2
│ original sql: <unknown>
│ exec mode: one row
└── • group (scalar)
└── • limit
│ count: 1
└── • filter
│ filter: y > 0
└── • scan
missing stats
table: xyz@xy
spans: FULL SCAN
·
index recommendations: 1
1. type: index creation
SQL command: CREATE INDEX ON xyz (y) STORING (z);

# Scalar subquery in filter is supported.
query T
Expand Down Expand Up @@ -1191,6 +1211,10 @@ vectorized: true
estimated row count: 1,000 (missing stats)
table: kv@kv_pkey
spans: FULL SCAN
·
index recommendations: 1
1. type: index creation
SQL command: CREATE INDEX ON kv (v);

query T
EXPLAIN (TYPES) SELECT v, count(*) FROM kv GROUP BY v ORDER BY count(*)
Expand All @@ -1215,6 +1239,10 @@ vectorized: true
estimated row count: 1,000 (missing stats)
table: kv@kv_pkey
spans: FULL SCAN
·
index recommendations: 1
1. type: index creation
SQL command: CREATE INDEX ON kv (v);

query T
EXPLAIN (TYPES) SELECT v, count(NULL) FROM kv GROUP BY v ORDER BY count(1)
Expand Down Expand Up @@ -1249,6 +1277,10 @@ vectorized: true
estimated row count: 1,000 (missing stats)
table: kv@kv_pkey
spans: FULL SCAN
·
index recommendations: 1
1. type: index creation
SQL command: CREATE INDEX ON kv (v);

# Check that filters propagate through no-op aggregation.
query T
Expand Down Expand Up @@ -1279,6 +1311,10 @@ vectorized: true
estimated row count: 1,000 (missing stats)
table: kv@kv_pkey
spans: FULL SCAN
·
index recommendations: 1
1. type: index creation
SQL command: CREATE INDEX ON kv (v);

# Verify that FILTER works.

Expand Down Expand Up @@ -1319,6 +1355,10 @@ vectorized: true
estimated row count: 1,000 (missing stats)
table: filter_test@filter_test_pkey
spans: FULL SCAN
·
index recommendations: 1
1. type: index creation
SQL command: CREATE INDEX ON filter_test (v) STORING (k);

query T
EXPLAIN (VERBOSE) SELECT count(*) FILTER (WHERE k > 5) FROM filter_test GROUP BY v
Expand Down Expand Up @@ -1348,6 +1388,10 @@ vectorized: true
estimated row count: 1,000 (missing stats)
table: filter_test@filter_test_pkey
spans: FULL SCAN
·
index recommendations: 1
1. type: index creation
SQL command: CREATE INDEX ON filter_test (v) STORING (k);

# Tests with * inside GROUP BY.
query T
Expand Down Expand Up @@ -1804,6 +1848,10 @@ vectorized: true
estimated row count: 1,000 (missing stats)
table: kv@kv_pkey
spans: FULL SCAN
·
index recommendations: 1
1. type: index creation
SQL command: CREATE INDEX ON kv (v);

query T
EXPLAIN (VERBOSE) SELECT k FROM kv ORDER BY s
Expand All @@ -1825,6 +1873,10 @@ vectorized: true
estimated row count: 1,000 (missing stats)
table: kv@kv_pkey
spans: FULL SCAN
·
index recommendations: 1
1. type: index creation
SQL command: CREATE INDEX ON kv (s);

query T
EXPLAIN (VERBOSE) SELECT concat_agg(s) FROM (SELECT s FROM kv ORDER BY k)
Expand Down Expand Up @@ -1866,6 +1918,10 @@ vectorized: true
estimated row count: 1,000 (missing stats)
table: kv@kv_pkey
spans: FULL SCAN
·
index recommendations: 1
1. type: index creation
SQL command: CREATE INDEX ON kv (s);

query T
EXPLAIN (VERBOSE) SELECT string_agg(s, ',') FROM (SELECT s FROM kv ORDER BY k)
Expand Down Expand Up @@ -1924,6 +1980,12 @@ vectorized: true
estimated row count: 1,000 (missing stats)
table: kv@kv_pkey
spans: FULL SCAN
·
index recommendations: 2
1. type: index creation
SQL command: CREATE INDEX ON kv (v);
2. type: index creation
SQL command: CREATE INDEX ON xyz (y);


# Regression test for #31882: make sure we don't incorrectly advertise an
Expand All @@ -1950,6 +2012,10 @@ vectorized: true
estimated row count: 1,000 (missing stats)
table: uvw@uvw
spans: FULL SCAN
·
index recommendations: 1
1. type: index creation
SQL command: CREATE INDEX ON uvw (w) STORING (u, v);

query T
EXPLAIN (VERBOSE) SELECT string_agg(s, ', ') FROM kv
Expand Down Expand Up @@ -2019,6 +2085,10 @@ vectorized: true
estimated row count: 1,000 (missing stats)
table: string_agg_test@string_agg_test_pkey
spans: FULL SCAN
·
index recommendations: 1
1. type: index creation
SQL command: CREATE INDEX ON string_agg_test (company_id) STORING (employee);

query T
EXPLAIN (VERBOSE)
Expand Down Expand Up @@ -2058,6 +2128,10 @@ vectorized: true
estimated row count: 1,000 (missing stats)
table: string_agg_test@string_agg_test_pkey
spans: FULL SCAN
·
index recommendations: 1
1. type: index creation
SQL command: CREATE INDEX ON string_agg_test (company_id) STORING (employee);

query T
EXPLAIN (VERBOSE)
Expand Down Expand Up @@ -2097,6 +2171,10 @@ vectorized: true
estimated row count: 1,000 (missing stats)
table: string_agg_test@string_agg_test_pkey
spans: FULL SCAN
·
index recommendations: 1
1. type: index creation
SQL command: CREATE INDEX ON string_agg_test (company_id) STORING (employee);

query T
EXPLAIN (VERBOSE)
Expand Down Expand Up @@ -2136,3 +2214,7 @@ vectorized: true
estimated row count: 1,000 (missing stats)
table: string_agg_test@string_agg_test_pkey
spans: FULL SCAN
·
index recommendations: 1
1. type: index creation
SQL command: CREATE INDEX ON string_agg_test (company_id) STORING (employee);
4 changes: 4 additions & 0 deletions pkg/sql/opt/exec/execbuilder/testdata/array
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,7 @@ vectorized: true
missing stats
table: t@t_pkey
spans: FULL SCAN
·
index recommendations: 1
1. type: index creation
SQL command: CREATE INDEX ON t (x) STORING (y, z);
Loading

0 comments on commit 5bea547

Please sign in to comment.