Commit 3105d70e authored by Rebecca Taft's avatar Rebecca Taft

sql: add support for ANALYZE <tablename>

This commit adds support for `ANALYZE <tablename>` by adding the
statement as syntactic sugar for the equivalent command
`CREATE STATISTICS "" FROM <tablename>`. This improves compatibility
with Postgres, and is needed to run the PostGIS tutorial as written.

Note that this commit does not add support for `ANALYZE` without a
table name. We can add support for that and other variants later if
needed, but it is not necessary for the PostGIS tutorial.

Fixes #49214

Release note (sql change): Added support for `ANALYZE <tablename>`,
which causes the database to collect statistics on the given table for
use by the optimizer. The functionality of this command is equivalent
to the existing command `CREATE STATISTICS "" FROM <tablename>`, but
it increases compatibility with Postgres by using the same syntax that
Postgres uses.
parent a18b32f9
......@@ -4,6 +4,7 @@ stmt_block ::=
stmt ::=
'HELPTOKEN'
| preparable_stmt
| analyze_stmt
| copy_from_stmt
| comment_stmt
| execute_stmt
......@@ -42,6 +43,10 @@ preparable_stmt ::=
| update_stmt
| upsert_stmt
analyze_stmt ::=
'ANALYZE' analyze_target
| 'ANALYSE' analyze_target
copy_from_stmt ::=
'COPY' table_name opt_column_list 'FROM' 'STDIN' opt_with_options
......@@ -206,6 +211,9 @@ update_stmt ::=
upsert_stmt ::=
opt_with_clause 'UPSERT' 'INTO' insert_target insert_rest returning_clause
analyze_target ::=
table_name
table_name ::=
db_object_name
......
......@@ -54,6 +54,14 @@ func (p *planner) CreateStatistics(ctx context.Context, n *tree.CreateStats) (pl
}, nil
}
// Analyze is syntactic sugar for CreateStatistics.
func (p *planner) Analyze(ctx context.Context, n *tree.Analyze) (planNode, error) {
return &createStatsNode{
CreateStats: tree.CreateStats{Table: n.Table},
p: p,
}, nil
}
// createStatsNode is a planNode implemented in terms of a function. The
// startJob function starts a Job during Start, and the remainder of the
// CREATE STATISTICS planning and execution is performed within the jobs
......
......@@ -107,9 +107,36 @@ NULL {b} 256 4 0 true
let $json_stats
SHOW STATISTICS USING JSON FOR TABLE data
# ANALYZE is syntactic sugar for CREATE STATISTICS with default columns.
statement ok
ANALYZE data
query TTIIIB colnames
SELECT
statistics_name,
column_names,
row_count,
distinct_count,
null_count,
histogram_id IS NOT NULL AS has_histogram
FROM
[SHOW STATISTICS FOR TABLE data];
----
statistics_name column_names row_count distinct_count null_count has_histogram
NULL {a} 256 4 0 true
NULL {a,b} 256 16 0 false
NULL {a,b,c} 256 64 0 false
NULL {a,b,c,d} 256 256 0 false
NULL {c} 256 4 0 true
NULL {c,d} 256 16 0 false
NULL {b} 256 4 0 false
NULL {d} 256 4 0 false
NULL {e} 256 2 0 true
statement ok
DELETE FROM system.table_statistics
# Restore the old stats.
statement ok
ALTER TABLE data INJECT STATISTICS '$json_stats'
......
......@@ -57,6 +57,8 @@ func buildOpaque(
plan, err = p.AlterRole(ctx, n)
case *tree.AlterSequence:
plan, err = p.AlterSequence(ctx, n)
case *tree.Analyze:
plan, err = p.Analyze(ctx, n)
case *tree.CommentOnColumn:
plan, err = p.CommentOnColumn(ctx, n)
case *tree.CommentOnDatabase:
......@@ -169,6 +171,7 @@ func init() {
&tree.AlterType{},
&tree.AlterSequence{},
&tree.AlterRole{},
&tree.Analyze{},
&tree.CommentOnColumn{},
&tree.CommentOnDatabase{},
&tree.CommentOnIndex{},
......
......@@ -80,6 +80,11 @@ func TestContextualHelp(t *testing.T) {
{`ALTER PARTITION ??`, `ALTER PARTITION`},
{`ALTER PARTITION p OF INDEX [email protected] ??`, `ALTER PARTITION`},
{`ANALYZE ??`, `ANALYZE`},
{`ANALYZE blah ??`, `ANALYZE`},
{`ANALYSE ??`, `ANALYZE`},
{`ANALYSE blah ??`, `ANALYZE`},
{`CANCEL ??`, `CANCEL`},
{`CANCEL JOB ??`, `CANCEL JOBS`},
{`CANCEL JOBS ??`, `CANCEL JOBS`},
......
......@@ -337,6 +337,8 @@ func TestParse(t *testing.T) {
{`CREATE STATISTICS a ON col1 FROM t`},
{`EXPLAIN CREATE STATISTICS a ON col1 FROM t`},
{`CREATE STATISTICS a FROM t`},
{`CREATE STATISTICS a FROM [53]`},
{`CREATE STATISTICS a ON col1, col2 FROM t`},
{`CREATE STATISTICS a ON col1 FROM d.t`},
{`CREATE STATISTICS a ON col1 FROM t`},
......@@ -344,6 +346,9 @@ func TestParse(t *testing.T) {
{`CREATE STATISTICS a ON col1 FROM t WITH OPTIONS AS OF SYSTEM TIME '2016-01-01'`},
{`CREATE STATISTICS a ON col1 FROM t WITH OPTIONS THROTTLING 0.1 AS OF SYSTEM TIME '2016-01-01'`},
{`ANALYZE t`},
{`ANALYZE db.sc.t`},
{`CREATE TYPE a AS ENUM ()`},
{`CREATE TYPE a AS ENUM ('a')`},
{`CREATE TYPE a AS ENUM ('a', 'b', 'c')`},
......@@ -516,6 +521,7 @@ func TestParse(t *testing.T) {
{`SHOW EXPERIMENTAL_REPLICA TRACE FOR SESSION`},
{`EXPLAIN SHOW EXPERIMENTAL_REPLICA TRACE FOR SESSION`},
{`SHOW STATISTICS FOR TABLE t`},
{`SHOW STATISTICS USING JSON FOR TABLE t`},
{`EXPLAIN SHOW STATISTICS FOR TABLE t`},
{`SHOW STATISTICS FOR TABLE d.t`},
{`SHOW HISTOGRAM 123`},
......@@ -1582,6 +1588,8 @@ func TestParse2(t *testing.T) {
{`CREATE STATISTICS a ON col1 FROM t AS OF SYSTEM TIME '2016-01-01'`,
`CREATE STATISTICS a ON col1 FROM t WITH OPTIONS AS OF SYSTEM TIME '2016-01-01'`},
{`ANALYSE t`, `ANALYZE t`},
{`SELECT TIMESTAMP WITHOUT TIME ZONE 'foo'`, `SELECT TIMESTAMP 'foo'`},
{`SELECT CAST('foo' AS TIMESTAMP WITHOUT TIME ZONE)`, `SELECT CAST('foo' AS TIMESTAMP)`},
{`SELECT CAST(1 AS "timestamp")`, `SELECT CAST(1 AS TIMESTAMP)`},
......@@ -2931,6 +2939,22 @@ DETAIL: source SQL:
CREATE STATISTICS a ON col1 FROM t WITH OPTIONS AS OF SYSTEM TIME '-1s' THROTTLING 0.1 AS OF SYSTEM TIME '-2s'
^`,
},
{
`ANALYZE`,
`at or near "EOF": syntax error
DETAIL: source SQL:
ANALYZE
^
HINT: try \h ANALYZE`,
},
{
`ANALYSE`,
`at or near "EOF": syntax error
DETAIL: source SQL:
ANALYSE
^
HINT: try \h ANALYZE`,
},
{
`ALTER PARTITION p OF TABLE [email protected] CONFIGURE ZONE USING num_replicas = 1`,
`at or near "idx": syntax error: index name should not be specified in ALTER PARTITION ... OF TABLE
......
......@@ -762,6 +762,7 @@ func (u *sqlSymUnion) alterTypeAddValuePlacement() *tree.AlterTypeAddValuePlacem
%type <tree.Statement> drop_view_stmt
%type <tree.Statement> drop_sequence_stmt
%type <tree.Statement> analyze_stmt
%type <tree.Statement> explain_stmt
%type <tree.Statement> prepare_stmt
%type <tree.Statement> preparable_stmt
......@@ -887,7 +888,7 @@ func (u *sqlSymUnion) alterTypeAddValuePlacement() *tree.AlterTypeAddValuePlacem
%type <str> schema_name
%type <*tree.UnresolvedName> table_pattern complex_table_pattern
%type <*tree.UnresolvedName> column_path prefixed_column_path column_path_with_star
%type <tree.TableExpr> insert_target create_stats_target
%type <tree.TableExpr> insert_target create_stats_target analyze_target
%type <*tree.TableIndexName> table_index_name
%type <tree.TableIndexNames> table_index_name_list
......@@ -1169,7 +1170,8 @@ stmt_block:
stmt:
HELPTOKEN { return helpWith(sqllex, "") }
| preparable_stmt // help texts in sub-rule
| preparable_stmt // help texts in sub-rule
| analyze_stmt // EXTEND WITH HELP: ANALYZE
| copy_from_stmt
| comment_stmt
| execute_stmt // EXTEND WITH HELP: EXECUTE
......@@ -2844,6 +2846,34 @@ table_name_list:
$$.val = append($1.tableNames(), name)
}
// %Help: ANALYZE - collect table statistics
// %Category: Misc
// %Text:
// ANALYZE <tablename>
//
// %SeeAlso: CREATE STATISTICS
analyze_stmt:
ANALYZE analyze_target
{
$$.val = &tree.Analyze{
Table: $2.tblExpr(),
}
}
| ANALYZE error // SHOW HELP: ANALYZE
| ANALYSE analyze_target
{
$$.val = &tree.Analyze{
Table: $2.tblExpr(),
}
}
| ANALYSE error // SHOW HELP: ANALYZE
analyze_target:
table_name
{
$$.val = $1.unresolvedObjectName()
}
// %Help: EXPLAIN - show the logical plan of a query
// %Category: Misc
// %Text:
......
......@@ -50,6 +50,7 @@ func (p *planner) prepareUsingOptimizer(ctx context.Context) (planFlags, error)
switch stmt.AST.(type) {
case *tree.AlterIndex, *tree.AlterTable, *tree.AlterSequence,
*tree.Analyze,
*tree.BeginTransaction,
*tree.CommentOnColumn, *tree.CommentOnDatabase, *tree.CommentOnIndex, *tree.CommentOnTable,
*tree.CommitTransaction,
......
// Copyright 2020 The Cockroach Authors.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
package tree
// Analyze represents an ANALYZE statement.
type Analyze struct {
Table TableExpr
}
// Format implements the NodeFormatter interface.
func (node *Analyze) Format(ctx *FmtCtx) {
ctx.WriteString("ANALYZE ")
ctx.FormatNode(node.Table)
}
......@@ -212,6 +212,12 @@ func (*AlterRole) cclOnlyStatement() {}
func (*AlterRole) hiddenFromShowQueries() {}
// StatementType implements the Statement interface.
func (*Analyze) StatementType() StatementType { return DDL }
// StatementTag returns a short string identifying the type of statement.
func (*Analyze) StatementTag() string { return "ANALYZE" }
// StatementType implements the Statement interface.
func (*Backup) StatementType() StatementType { return Rows }
......@@ -919,6 +925,7 @@ func (n *AlterTableSetNotNull) String() string { return AsString(n) }
func (n *AlterType) String() string { return AsString(n) }
func (n *AlterRole) String() string { return AsString(n) }
func (n *AlterSequence) String() string { return AsString(n) }
func (n *Analyze) String() string { return AsString(n) }
func (n *Backup) String() string { return AsString(n) }
func (n *BeginTransaction) String() string { return AsString(n) }
func (n *ControlJobs) String() string { return AsString(n) }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment