mirror of https://github.com/citusdata/citus.git
Merge pull request #4196 from citusdata/support-explain-analyze-wal
Support EXPLAIN(ANALYZE, WAL)pull/4213/head
commit
6a341b6ab8
|
@ -83,6 +83,7 @@ typedef struct
|
||||||
bool verbose;
|
bool verbose;
|
||||||
bool costs;
|
bool costs;
|
||||||
bool buffers;
|
bool buffers;
|
||||||
|
bool wal;
|
||||||
bool timing;
|
bool timing;
|
||||||
bool summary;
|
bool summary;
|
||||||
ExplainFormat format;
|
ExplainFormat format;
|
||||||
|
@ -91,7 +92,7 @@ typedef struct
|
||||||
|
|
||||||
/* EXPLAIN flags of current distributed explain */
|
/* EXPLAIN flags of current distributed explain */
|
||||||
static ExplainOptions CurrentDistributedQueryExplainOptions = {
|
static ExplainOptions CurrentDistributedQueryExplainOptions = {
|
||||||
0, 0, 0, 0, 0, EXPLAIN_FORMAT_TEXT
|
0, 0, 0, 0, 0, 0, EXPLAIN_FORMAT_TEXT
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Result for a single remote EXPLAIN command */
|
/* Result for a single remote EXPLAIN command */
|
||||||
|
@ -904,12 +905,18 @@ BuildRemoteExplainQuery(char *queryString, ExplainState *es)
|
||||||
|
|
||||||
appendStringInfo(explainQuery,
|
appendStringInfo(explainQuery,
|
||||||
"EXPLAIN (ANALYZE %s, VERBOSE %s, "
|
"EXPLAIN (ANALYZE %s, VERBOSE %s, "
|
||||||
"COSTS %s, BUFFERS %s, TIMING %s, SUMMARY %s, "
|
"COSTS %s, BUFFERS %s, "
|
||||||
"FORMAT %s) %s",
|
#if PG_VERSION_NUM >= PG_VERSION_13
|
||||||
|
"WAL %s, "
|
||||||
|
#endif
|
||||||
|
"TIMING %s, SUMMARY %s, FORMAT %s) %s",
|
||||||
es->analyze ? "TRUE" : "FALSE",
|
es->analyze ? "TRUE" : "FALSE",
|
||||||
es->verbose ? "TRUE" : "FALSE",
|
es->verbose ? "TRUE" : "FALSE",
|
||||||
es->costs ? "TRUE" : "FALSE",
|
es->costs ? "TRUE" : "FALSE",
|
||||||
es->buffers ? "TRUE" : "FALSE",
|
es->buffers ? "TRUE" : "FALSE",
|
||||||
|
#if PG_VERSION_NUM >= PG_VERSION_13
|
||||||
|
es->wal ? "TRUE" : "FALSE",
|
||||||
|
#endif
|
||||||
es->timing ? "TRUE" : "FALSE",
|
es->timing ? "TRUE" : "FALSE",
|
||||||
es->summary ? "TRUE" : "FALSE",
|
es->summary ? "TRUE" : "FALSE",
|
||||||
formatStr,
|
formatStr,
|
||||||
|
@ -1005,6 +1012,9 @@ worker_save_query_explain_analyze(PG_FUNCTION_ARGS)
|
||||||
|
|
||||||
/* use the same defaults as NewExplainState() for following options */
|
/* use the same defaults as NewExplainState() for following options */
|
||||||
es->buffers = ExtractFieldBoolean(explainOptions, "buffers", es->buffers);
|
es->buffers = ExtractFieldBoolean(explainOptions, "buffers", es->buffers);
|
||||||
|
#if PG_VERSION_NUM >= PG_VERSION_13
|
||||||
|
es->wal = ExtractFieldBoolean(explainOptions, "wal", es->wal);
|
||||||
|
#endif
|
||||||
es->costs = ExtractFieldBoolean(explainOptions, "costs", es->costs);
|
es->costs = ExtractFieldBoolean(explainOptions, "costs", es->costs);
|
||||||
es->summary = ExtractFieldBoolean(explainOptions, "summary", es->summary);
|
es->summary = ExtractFieldBoolean(explainOptions, "summary", es->summary);
|
||||||
es->verbose = ExtractFieldBoolean(explainOptions, "verbose", es->verbose);
|
es->verbose = ExtractFieldBoolean(explainOptions, "verbose", es->verbose);
|
||||||
|
@ -1206,6 +1216,9 @@ CitusExplainOneQuery(Query *query, int cursorOptions, IntoClause *into,
|
||||||
/* save the flags of current EXPLAIN command */
|
/* save the flags of current EXPLAIN command */
|
||||||
CurrentDistributedQueryExplainOptions.costs = es->costs;
|
CurrentDistributedQueryExplainOptions.costs = es->costs;
|
||||||
CurrentDistributedQueryExplainOptions.buffers = es->buffers;
|
CurrentDistributedQueryExplainOptions.buffers = es->buffers;
|
||||||
|
#if PG_VERSION_NUM >= PG_VERSION_13
|
||||||
|
CurrentDistributedQueryExplainOptions.wal = es->wal;
|
||||||
|
#endif
|
||||||
CurrentDistributedQueryExplainOptions.verbose = es->verbose;
|
CurrentDistributedQueryExplainOptions.verbose = es->verbose;
|
||||||
CurrentDistributedQueryExplainOptions.summary = es->summary;
|
CurrentDistributedQueryExplainOptions.summary = es->summary;
|
||||||
CurrentDistributedQueryExplainOptions.timing = es->timing;
|
CurrentDistributedQueryExplainOptions.timing = es->timing;
|
||||||
|
@ -1482,11 +1495,18 @@ WrapQueryForExplainAnalyze(const char *queryString, TupleDesc tupleDesc)
|
||||||
}
|
}
|
||||||
|
|
||||||
StringInfo explainOptions = makeStringInfo();
|
StringInfo explainOptions = makeStringInfo();
|
||||||
appendStringInfo(explainOptions, "{\"verbose\": %s, \"costs\": %s, \"buffers\": %s, "
|
appendStringInfo(explainOptions,
|
||||||
"\"timing\": %s, \"summary\": %s, \"format\": \"%s\"}",
|
"{\"verbose\": %s, \"costs\": %s, \"buffers\": %s, "
|
||||||
|
#if PG_VERSION_NUM >= PG_VERSION_13
|
||||||
|
"\"wal\": %s, "
|
||||||
|
#endif
|
||||||
|
"\"timing\": %s, \"summary\": %s, \"format\": \"%s\"}",
|
||||||
CurrentDistributedQueryExplainOptions.verbose ? "true" : "false",
|
CurrentDistributedQueryExplainOptions.verbose ? "true" : "false",
|
||||||
CurrentDistributedQueryExplainOptions.costs ? "true" : "false",
|
CurrentDistributedQueryExplainOptions.costs ? "true" : "false",
|
||||||
CurrentDistributedQueryExplainOptions.buffers ? "true" : "false",
|
CurrentDistributedQueryExplainOptions.buffers ? "true" : "false",
|
||||||
|
#if PG_VERSION_NUM >= PG_VERSION_13
|
||||||
|
CurrentDistributedQueryExplainOptions.wal ? "true" : "false",
|
||||||
|
#endif
|
||||||
CurrentDistributedQueryExplainOptions.timing ? "true" : "false",
|
CurrentDistributedQueryExplainOptions.timing ? "true" : "false",
|
||||||
CurrentDistributedQueryExplainOptions.summary ? "true" : "false",
|
CurrentDistributedQueryExplainOptions.summary ? "true" : "false",
|
||||||
ExplainFormatStr(CurrentDistributedQueryExplainOptions.format));
|
ExplainFormatStr(CurrentDistributedQueryExplainOptions.format));
|
||||||
|
@ -1632,7 +1652,10 @@ ExplainWorkerPlan(PlannedStmt *plannedstmt, DestReceiver *dest, ExplainState *es
|
||||||
|
|
||||||
if (es->buffers)
|
if (es->buffers)
|
||||||
instrument_option |= INSTRUMENT_BUFFERS;
|
instrument_option |= INSTRUMENT_BUFFERS;
|
||||||
|
#if PG_VERSION_NUM >= PG_VERSION_13
|
||||||
|
if (es->wal)
|
||||||
|
instrument_option |= INSTRUMENT_WAL;
|
||||||
|
#endif
|
||||||
/*
|
/*
|
||||||
* We always collect timing for the entire statement, even when node-level
|
* We always collect timing for the entire statement, even when node-level
|
||||||
* timing is off, so we don't look at es->timing here. (We could skip
|
* timing is off, so we don't look at es->timing here. (We could skip
|
||||||
|
|
|
@ -170,15 +170,97 @@ SELECT create_distributed_table('test_table', 'a');
|
||||||
-- we currently don't support this
|
-- we currently don't support this
|
||||||
CREATE INDEX test_table_index ON test_table USING gist (b tsvector_ops(siglen = 100));
|
CREATE INDEX test_table_index ON test_table USING gist (b tsvector_ops(siglen = 100));
|
||||||
ERROR: citus currently doesn't support operator class parameters in indexes
|
ERROR: citus currently doesn't support operator class parameters in indexes
|
||||||
|
-- testing WAL
|
||||||
|
CREATE TABLE test_wal(a int, b int);
|
||||||
|
-- test WAL without ANALYZE, this should raise an error
|
||||||
|
EXPLAIN (WAL) INSERT INTO test_wal VALUES(1,11);
|
||||||
|
ERROR: EXPLAIN option WAL requires ANALYZE
|
||||||
|
-- test WAL working properly for router queries
|
||||||
|
EXPLAIN (ANALYZE TRUE, WAL TRUE, COSTS FALSE, SUMMARY FALSE, BUFFERS FALSE, TIMING FALSE)
|
||||||
|
INSERT INTO test_wal VALUES(1,11);
|
||||||
|
QUERY PLAN
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
Insert on test_wal (actual rows=0 loops=1)
|
||||||
|
WAL: records=1 bytes=63
|
||||||
|
-> Result (actual rows=1 loops=1)
|
||||||
|
(3 rows)
|
||||||
|
|
||||||
|
SELECT create_distributed_table('test_wal', 'a');
|
||||||
|
NOTICE: Copying data from local table...
|
||||||
|
NOTICE: copying the data has completed
|
||||||
|
DETAIL: The local data in the table is no longer visible, but is still on disk.
|
||||||
|
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$test_pg13.test_wal$$)
|
||||||
|
create_distributed_table
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
EXPLAIN (ANALYZE TRUE, WAL TRUE, COSTS FALSE, SUMMARY FALSE, BUFFERS FALSE, TIMING FALSE)
|
||||||
|
INSERT INTO test_wal VALUES(2,22);
|
||||||
|
QUERY PLAN
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
Custom Scan (Citus Adaptive) (actual rows=0 loops=1)
|
||||||
|
Task Count: 1
|
||||||
|
Tasks Shown: All
|
||||||
|
-> Task
|
||||||
|
Node: host=localhost port=xxxxx dbname=regression
|
||||||
|
-> Insert on test_wal_65013 (actual rows=0 loops=1)
|
||||||
|
WAL: records=1 bytes=63
|
||||||
|
-> Result (actual rows=1 loops=1)
|
||||||
|
(8 rows)
|
||||||
|
|
||||||
|
-- Test WAL working for multi-shard query
|
||||||
|
SET citus.explain_all_tasks TO on;
|
||||||
|
EXPLAIN (ANALYZE TRUE, WAL TRUE, COSTS FALSE, SUMMARY FALSE, BUFFERS FALSE, TIMING FALSE)
|
||||||
|
INSERT INTO test_wal VALUES(3,33),(4,44),(5,55) RETURNING *;
|
||||||
|
QUERY PLAN
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
Custom Scan (Citus Adaptive) (actual rows=3 loops=1)
|
||||||
|
Task Count: 1
|
||||||
|
Tuple data received from nodes: 9 bytes
|
||||||
|
Tasks Shown: All
|
||||||
|
-> Task
|
||||||
|
Tuple data received from node: 9 bytes
|
||||||
|
Node: host=localhost port=xxxxx dbname=regression
|
||||||
|
-> Insert on test_wal_65012 citus_table_alias (actual rows=3 loops=1)
|
||||||
|
WAL: records=3 bytes=189
|
||||||
|
-> Values Scan on "*VALUES*" (actual rows=3 loops=1)
|
||||||
|
(10 rows)
|
||||||
|
|
||||||
|
-- make sure WAL works in distributed subplans
|
||||||
|
EXPLAIN (ANALYZE TRUE, WAL TRUE, COSTS FALSE, SUMMARY FALSE, BUFFERS FALSE, TIMING FALSE)
|
||||||
|
WITH cte_1 AS (INSERT INTO test_wal VALUES(6,66),(7,77),(8,88) RETURNING *)
|
||||||
|
SELECT * FROM cte_1;
|
||||||
|
QUERY PLAN
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
Custom Scan (Citus Adaptive) (actual rows=3 loops=1)
|
||||||
|
-> Distributed Subplan XXX_1
|
||||||
|
Intermediate Data Size: 54 bytes
|
||||||
|
Result destination: Write locally
|
||||||
|
-> Custom Scan (Citus Adaptive) (actual rows=3 loops=1)
|
||||||
|
Task Count: 2
|
||||||
|
Tuple data received from nodes: 9 bytes
|
||||||
|
Tasks Shown: All
|
||||||
|
-> Task
|
||||||
|
Tuple data received from node: 6 bytes
|
||||||
|
Node: host=localhost port=xxxxx dbname=regression
|
||||||
|
-> Insert on test_wal_65012 citus_table_alias (actual rows=2 loops=1)
|
||||||
|
WAL: records=2 bytes=126
|
||||||
|
-> Values Scan on "*VALUES*" (actual rows=2 loops=1)
|
||||||
|
-> Task
|
||||||
|
Tuple data received from node: 3 bytes
|
||||||
|
Node: host=localhost port=xxxxx dbname=regression
|
||||||
|
-> Insert on test_wal_65013 citus_table_alias (actual rows=1 loops=1)
|
||||||
|
WAL: records=1 bytes=63
|
||||||
|
-> Result (actual rows=1 loops=1)
|
||||||
|
Task Count: 1
|
||||||
|
Tuple data received from nodes: 9 bytes
|
||||||
|
Tasks Shown: All
|
||||||
|
-> Task
|
||||||
|
Tuple data received from node: 9 bytes
|
||||||
|
Node: host=localhost port=xxxxx dbname=regression
|
||||||
|
-> Function Scan on read_intermediate_result intermediate_result (actual rows=3 loops=1)
|
||||||
|
(27 rows)
|
||||||
|
|
||||||
|
SET client_min_messages TO WARNING;
|
||||||
drop schema test_pg13 cascade;
|
drop schema test_pg13 cascade;
|
||||||
NOTICE: drop cascades to 10 other objects
|
|
||||||
DETAIL: drop cascades to table dist_table
|
|
||||||
drop cascades to table generated_col_table
|
|
||||||
drop cascades to view v
|
|
||||||
drop cascades to table ab
|
|
||||||
drop cascades to table text_table
|
|
||||||
drop cascades to function myvarcharout(myvarchar)
|
|
||||||
drop cascades to type myvarchar
|
|
||||||
drop cascades to function myvarcharin(cstring,oid,integer)
|
|
||||||
drop cascades to table my_table
|
|
||||||
drop cascades to table test_table
|
|
||||||
|
|
|
@ -94,4 +94,26 @@ SELECT create_distributed_table('test_table', 'a');
|
||||||
-- we currently don't support this
|
-- we currently don't support this
|
||||||
CREATE INDEX test_table_index ON test_table USING gist (b tsvector_ops(siglen = 100));
|
CREATE INDEX test_table_index ON test_table USING gist (b tsvector_ops(siglen = 100));
|
||||||
|
|
||||||
|
-- testing WAL
|
||||||
|
CREATE TABLE test_wal(a int, b int);
|
||||||
|
-- test WAL without ANALYZE, this should raise an error
|
||||||
|
EXPLAIN (WAL) INSERT INTO test_wal VALUES(1,11);
|
||||||
|
-- test WAL working properly for router queries
|
||||||
|
EXPLAIN (ANALYZE TRUE, WAL TRUE, COSTS FALSE, SUMMARY FALSE, BUFFERS FALSE, TIMING FALSE)
|
||||||
|
INSERT INTO test_wal VALUES(1,11);
|
||||||
|
SELECT create_distributed_table('test_wal', 'a');
|
||||||
|
EXPLAIN (ANALYZE TRUE, WAL TRUE, COSTS FALSE, SUMMARY FALSE, BUFFERS FALSE, TIMING FALSE)
|
||||||
|
INSERT INTO test_wal VALUES(2,22);
|
||||||
|
|
||||||
|
-- Test WAL working for multi-shard query
|
||||||
|
SET citus.explain_all_tasks TO on;
|
||||||
|
EXPLAIN (ANALYZE TRUE, WAL TRUE, COSTS FALSE, SUMMARY FALSE, BUFFERS FALSE, TIMING FALSE)
|
||||||
|
INSERT INTO test_wal VALUES(3,33),(4,44),(5,55) RETURNING *;
|
||||||
|
|
||||||
|
-- make sure WAL works in distributed subplans
|
||||||
|
EXPLAIN (ANALYZE TRUE, WAL TRUE, COSTS FALSE, SUMMARY FALSE, BUFFERS FALSE, TIMING FALSE)
|
||||||
|
WITH cte_1 AS (INSERT INTO test_wal VALUES(6,66),(7,77),(8,88) RETURNING *)
|
||||||
|
SELECT * FROM cte_1;
|
||||||
|
|
||||||
|
SET client_min_messages TO WARNING;
|
||||||
drop schema test_pg13 cascade;
|
drop schema test_pg13 cascade;
|
||||||
|
|
Loading…
Reference in New Issue