Skip to content

Commit af57ee4

Browse files
shlomi-noachdbussink
authored andcommitted
8.0.34: New ANALYZE TABLE ... QUERY HISTOGRAM syntax to fetch histograms without writing to system tables (mysql#111)
* New `ANALYZE TABLE ... QUERY HISTOGRAM` syntax to fetch histograms without writing to system tables (mysql#109) * ANALYZE TABLE ... QUERY HISTOGRAM Signed-off-by: Shlomi Noach <[email protected]> * validate 'WITH [n] BUCKETS' syntax works Signed-off-by: Shlomi Noach <[email protected]> --------- Signed-off-by: Shlomi Noach <[email protected]> * New `ANALYZE TABLE ... QUERY HISTOGRAM` syntax to fetch histograms without writing to system tables (mysql#109) * ANALYZE TABLE ... QUERY HISTOGRAM Signed-off-by: Shlomi Noach <[email protected]> * validate 'WITH [n] BUCKETS' syntax works Signed-off-by: Shlomi Noach <[email protected]> --------- Signed-off-by: Shlomi Noach <[email protected]> --------- Signed-off-by: Shlomi Noach <[email protected]>
1 parent ee56bd7 commit af57ee4

File tree

7 files changed

+205
-11
lines changed

7 files changed

+205
-11
lines changed

mysql-test/r/query_histogram.result

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
drop table if exists t0;
2+
create table t0 (id int auto_increment primary key, i int);
3+
insert into t0 values (1, 1);
4+
insert into t0 values (2, 2);
5+
# Run a standard ANALZYE TABLE ... UPDATE HISTOGRAM
6+
analyze local table t0 update histogram on i;
7+
Table Op Msg_type Msg_text
8+
test.t0 histogram status Histogram statistics created for column 'i'.
9+
SELECT COUNT(*) AS should_be_1 FROM information_schema.COLUMN_STATISTICS;
10+
should_be_1
11+
1
12+
analyze table t0 drop histogram on i;
13+
Table Op Msg_type Msg_text
14+
test.t0 histogram status Histogram statistics removed for column 'i'.
15+
SELECT COUNT(*) AS should_be_0 FROM information_schema.COLUMN_STATISTICS;
16+
should_be_0
17+
0
18+
# Run ANALZYE TABLE ... QUERY HISTOGRAM
19+
analyze local table t0 query histogram on i;
20+
Table Op Msg_type Msg_text
21+
test.t0 histogram histogram_result {"buckets": [[1, 0.5], [2, 1.0]], "data-type": "int", "null-values": 0.0, "collation-id": 8, "last-updated": "redacted", "sampling-rate": 1.0, "histogram-type": "singleton", "number-of-buckets-specified": 100}
22+
SELECT COUNT(*) AS should_be_0 FROM information_schema.COLUMN_STATISTICS;
23+
should_be_0
24+
0
25+
analyze local table t0 drop histogram on i;
26+
Table Op Msg_type Msg_text
27+
test.t0 histogram Error No histogram statistics found for column 'i'.
28+
# Validate that standard ANALZYE TABLE ... UPDATE|DROP HISTOGRAM does not work in @@read_only=1 mode
29+
set @@global.read_only=1;
30+
analyze table t0 update histogram on i;
31+
Table Op Msg_type Msg_text
32+
histogram Error The server is in read-only mode.
33+
analyze local table t0 update histogram on i;
34+
Table Op Msg_type Msg_text
35+
histogram Error The server is in read-only mode.
36+
analyze local table t0 drop histogram on i;
37+
Table Op Msg_type Msg_text
38+
histogram Error The server is in read-only mode.
39+
# Validate ANALZYE TABLE ... QUERY HISTOGRAM is allowed in @@read_only=1 mode
40+
set @@global.read_only=1;
41+
analyze local table t0 query histogram on i;
42+
Table Op Msg_type Msg_text
43+
test.t0 histogram histogram_result {"buckets": [[1, 0.5], [2, 1.0]], "data-type": "int", "null-values": 0.0, "collation-id": 8, "last-updated": "redacted", "sampling-rate": 1.0, "histogram-type": "singleton", "number-of-buckets-specified": 100}
44+
SELECT COUNT(*) AS should_be_0 FROM information_schema.COLUMN_STATISTICS;
45+
should_be_0
46+
0
47+
analyze table t0 query histogram on i;
48+
Table Op Msg_type Msg_text
49+
histogram Error The server is in read-only mode.
50+
analyze table t0 update histogram on i;
51+
Table Op Msg_type Msg_text
52+
histogram Error The server is in read-only mode.
53+
analyze local table t0 drop histogram on i;
54+
Table Op Msg_type Msg_text
55+
histogram Error The server is in read-only mode.
56+
set @@global.read_only=0;
57+
# QUERY HISTOGRAM for two columns
58+
alter table t0 add column j int;
59+
update t0 set j=i*100;
60+
analyze local table t0 query histogram on i, j;
61+
Table Op Msg_type Msg_text
62+
test.t0 histogram histogram_result {"buckets": [[1, 0.5], [2, 1.0]], "data-type": "int", "null-values": 0.0, "collation-id": 8, "last-updated": "redacted", "sampling-rate": 1.0, "histogram-type": "singleton", "number-of-buckets-specified": 100}
63+
test.t0 histogram histogram_result {"buckets": [[100, 0.5], [200, 1.0]], "data-type": "int", "null-values": 0.0, "collation-id": 8, "last-updated": "redacted", "sampling-rate": 1.0, "histogram-type": "singleton", "number-of-buckets-specified": 100}
64+
# QUERY HISTOGRAM specifying buckets
65+
insert into t0 select null, 0, 0 from t0;
66+
insert into t0 select null, 0, 0 from t0;
67+
insert into t0 select null, 0, 0 from t0;
68+
insert into t0 select null, 0, 0 from t0;
69+
insert into t0 select null, 0, 0 from t0;
70+
insert into t0 select null, 0, 0 from t0;
71+
insert into t0 select null, 0, 0 from t0;
72+
insert into t0 select null, 0, 0 from t0;
73+
insert into t0 select null, 0, 0 from t0;
74+
insert into t0 select null, 0, 0 from t0;
75+
update t0 set i=id;
76+
analyze local table t0 query histogram on i with 16 buckets;
77+
Table Op Msg_type Msg_text
78+
test.t0 histogram histogram_result {"number-of-buckets-specified": 16}
79+
# Cleanup
80+
drop table if exists t0;

mysql-test/t/query_histogram.test

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#
2+
# Test of ANALYZE TABLE ... QUERY HISTOGRAM
3+
#
4+
5+
--source include/count_sessions.inc
6+
7+
--disable_warnings
8+
drop table if exists t0;
9+
--enable_warnings
10+
11+
create table t0 (id int auto_increment primary key, i int);
12+
13+
insert into t0 values (1, 1);
14+
insert into t0 values (2, 2);
15+
16+
--echo # Run a standard ANALZYE TABLE ... UPDATE HISTOGRAM
17+
analyze local table t0 update histogram on i;
18+
SELECT COUNT(*) AS should_be_1 FROM information_schema.COLUMN_STATISTICS;
19+
analyze table t0 drop histogram on i;
20+
SELECT COUNT(*) AS should_be_0 FROM information_schema.COLUMN_STATISTICS;
21+
22+
--echo # Run ANALZYE TABLE ... QUERY HISTOGRAM
23+
--replace_regex /"last-updated": ".*?"/"last-updated": "redacted"/
24+
analyze local table t0 query histogram on i;
25+
SELECT COUNT(*) AS should_be_0 FROM information_schema.COLUMN_STATISTICS;
26+
analyze local table t0 drop histogram on i;
27+
28+
--echo # Validate that standard ANALZYE TABLE ... UPDATE|DROP HISTOGRAM does not work in @@read_only=1 mode
29+
set @@global.read_only=1;
30+
analyze table t0 update histogram on i;
31+
analyze local table t0 update histogram on i;
32+
analyze local table t0 drop histogram on i;
33+
34+
--echo # Validate ANALZYE TABLE ... QUERY HISTOGRAM is allowed in @@read_only=1 mode
35+
set @@global.read_only=1;
36+
--replace_regex /"last-updated": ".*?"/"last-updated": "redacted"/
37+
analyze local table t0 query histogram on i;
38+
SELECT COUNT(*) AS should_be_0 FROM information_schema.COLUMN_STATISTICS;
39+
analyze table t0 query histogram on i;
40+
analyze table t0 update histogram on i;
41+
analyze local table t0 drop histogram on i;
42+
set @@global.read_only=0;
43+
44+
--echo # QUERY HISTOGRAM for two columns
45+
alter table t0 add column j int;
46+
update t0 set j=i*100;
47+
--replace_regex /"last-updated": ".*?"/"last-updated": "redacted"/
48+
analyze local table t0 query histogram on i, j;
49+
50+
--echo # QUERY HISTOGRAM specifying buckets
51+
insert into t0 select null, 0, 0 from t0;
52+
insert into t0 select null, 0, 0 from t0;
53+
insert into t0 select null, 0, 0 from t0;
54+
insert into t0 select null, 0, 0 from t0;
55+
insert into t0 select null, 0, 0 from t0;
56+
insert into t0 select null, 0, 0 from t0;
57+
insert into t0 select null, 0, 0 from t0;
58+
insert into t0 select null, 0, 0 from t0;
59+
insert into t0 select null, 0, 0 from t0;
60+
insert into t0 select null, 0, 0 from t0;
61+
update t0 set i=id;
62+
--replace_regex /"buckets".*"number-of-buckets-specified"/"number-of-buckets-specified"/
63+
analyze local table t0 query histogram on i with 16 buckets;
64+
65+
--echo # Cleanup
66+
drop table if exists t0;
67+

sql/histograms/histogram.cc

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1256,12 +1256,16 @@ static bool fill_value_maps(
12561256
}
12571257

12581258
bool update_histogram(THD *thd, Table_ref *table, const columns_set &columns,
1259+
const bool query_histogram,
12591260
int num_buckets, LEX_STRING data, results_map &results) {
12601261
dd::cache::Dictionary_client::Auto_releaser auto_releaser(thd->dd_client());
12611262

12621263
// Read only should have been stopped at an earlier stage.
1263-
assert(!check_readonly(thd, false));
1264-
assert(!thd->tx_read_only);
1264+
// PlanetScale patch: allow `ANALYZE TABLE ... QUERY HISTOGRAM` in read_only mode
1265+
if (!query_histogram) {
1266+
assert(!check_readonly(thd, false));
1267+
assert(!thd->tx_read_only);
1268+
}
12651269

12661270
assert(results.empty());
12671271
assert(!columns.empty());
@@ -1417,13 +1421,22 @@ bool update_histogram(THD *thd, Table_ref *table, const columns_set &columns,
14171421
*down_cast<Json_object *>(dom.get()), &context);
14181422

14191423
// Store it to persistent storage.
1420-
if (histogram == nullptr || histogram->store_histogram(thd)) {
1424+
if (histogram == nullptr || ((!query_histogram) && histogram->store_histogram(thd))) {
14211425
my_error(ER_UNABLE_TO_BUILD_HISTOGRAM, MYF(0), field->field_name,
14221426
table->db, table->table_name);
14231427
return true;
14241428
}
1425-
1426-
results.emplace(col_name, Message::HISTOGRAM_CREATED);
1429+
if (query_histogram) {
1430+
Json_object json_object;
1431+
histogram->histogram_to_json(&json_object);
1432+
Json_wrapper json_wrapper(&json_object);
1433+
json_wrapper.set_alias();
1434+
String str;
1435+
json_wrapper.to_string(&str, true, String().ptr(), JsonDocumentDefaultDepthHandler);
1436+
results.emplace(str.c_ptr(), Message::HISTOGRAM_QUERY_RESULT);
1437+
} else {
1438+
results.emplace(col_name, Message::HISTOGRAM_CREATED);
1439+
}
14271440

14281441
bool ret = trans_commit_stmt(thd) || trans_commit(thd);
14291442
close_thread_tables(thd);
@@ -1490,12 +1503,21 @@ bool update_histogram(THD *thd, Table_ref *table, const columns_set &columns,
14901503
table->db, table->table_name);
14911504
return true;
14921505
/* purecov: end */
1493-
} else if (histogram->store_histogram(thd)) {
1506+
} else if ((!query_histogram) && histogram->store_histogram(thd)) {
14941507
// errors have already been reported
14951508
return true; /* purecov: deadcode */
14961509
}
1497-
1498-
results.emplace(col_name, Message::HISTOGRAM_CREATED);
1510+
if (query_histogram) {
1511+
Json_object json_object;
1512+
histogram->histogram_to_json(&json_object);
1513+
Json_wrapper json_wrapper(&json_object);
1514+
json_wrapper.set_alias();
1515+
String str;
1516+
json_wrapper.to_string(&str, true, String().ptr(), JsonDocumentDefaultDepthHandler);
1517+
results.emplace(str.c_ptr(), Message::HISTOGRAM_QUERY_RESULT);
1518+
} else {
1519+
results.emplace(col_name, Message::HISTOGRAM_CREATED);
1520+
}
14991521
}
15001522

15011523
bool ret = trans_commit_stmt(thd) || trans_commit(thd);

sql/histograms/histogram.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ enum class Message {
9292
HISTOGRAM_DELETED,
9393
SERVER_READ_ONLY,
9494
MULTIPLE_COLUMNS_SPECIFIED,
95+
HISTOGRAM_QUERY_RESULT,
9596

9697
// JSON validation errors. See Error_context.
9798
JSON_FORMAT_ERROR,
@@ -694,6 +695,7 @@ Histogram *build_histogram(MEM_ROOT *mem_root, const Value_map<T> &value_map,
694695
@param thd Thread handler.
695696
@param table The table where we should look for the columns/data.
696697
@param columns Columns specified by the user.
698+
@param query_histogram Whether histogram JSON should return in the result set.
697699
@param num_buckets The maximum number of buckets to create in each
698700
histogram.
699701
@param data The histogram json literal for update
@@ -702,6 +704,7 @@ Histogram *build_histogram(MEM_ROOT *mem_root, const Value_map<T> &value_map,
702704
@return false on success, true on error.
703705
*/
704706
bool update_histogram(THD *thd, Table_ref *table, const columns_set &columns,
707+
const bool query_histogram,
705708
int num_buckets, LEX_STRING data, results_map &results);
706709

707710
/**

sql/sql_admin.cc

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,11 @@ bool Sql_cmd_analyze_table::send_histogram_results(
391391
message.append(pair.first);
392392
message.append("'.");
393393
break;
394+
case histograms::Message::HISTOGRAM_QUERY_RESULT:
395+
// PlanetScale patch: the value of `Msg_text` column is the histogram's JSON.
396+
message_type.assign("histogram_result");
397+
message.append(pair.first);
398+
break;
394399
// Error messages
395400
case histograms::Message::FIELD_NOT_FOUND:
396401
message_type.assign("Error");
@@ -625,6 +630,7 @@ bool Sql_cmd_analyze_table::update_histogram(THD *thd, Table_ref *table,
625630
fields.emplace(column->ptr(), column->length());
626631

627632
return histograms::update_histogram(thd, table, fields,
633+
(get_histogram_command() == Histogram_command::QUERY_HISTOGRAM),
628634
get_histogram_buckets(),
629635
get_histogram_data_string(), results);
630636
}
@@ -1631,12 +1637,14 @@ bool Sql_cmd_analyze_table::handle_histogram_command(THD *thd,
16311637
if (table->next_local != nullptr) {
16321638
/*
16331639
Only one table can be specified for
1634-
ANALYZE TABLE ... UPDATE/DROP HISTOGRAM
1640+
ANALYZE TABLE ... UPDATE/DROP/QUERY HISTOGRAM
16351641
*/
16361642
results.emplace("", histograms::Message::MULTIPLE_TABLES_SPECIFIED);
16371643
res = true;
16381644
} else {
1639-
if (read_only || thd->tx_read_only) {
1645+
// PlanetScale patch: allow `ANALYZE TABLE ... QUERY HISTOGRAM` in read_only mode
1646+
if ((read_only || thd->tx_read_only) &&
1647+
!(thd->lex->no_write_to_binlog && (get_histogram_command() == Histogram_command::QUERY_HISTOGRAM))) {
16401648
// Do not try to update histograms when in read_only mode.
16411649
results.emplace("", histograms::Message::SERVER_READ_ONLY);
16421650
res = false;
@@ -1665,6 +1673,10 @@ bool Sql_cmd_analyze_table::handle_histogram_command(THD *thd,
16651673

16661674
dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client());
16671675
switch (get_histogram_command()) {
1676+
case Histogram_command::QUERY_HISTOGRAM:
1677+
// PlanetScale patch: compute histogram but do not write it to system tables.
1678+
// Instead, return it as a result set.
1679+
[[fallthrough]];
16681680
case Histogram_command::UPDATE_HISTOGRAM:
16691681
res = acquire_shared_backup_lock(thd,
16701682
thd->variables.lock_wait_timeout) ||

sql/sql_admin.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ class Sql_cmd_analyze_table : public Sql_cmd_ddl_table {
7070
NONE, ///< Neither UPDATE or DROP histogram is specified
7171
UPDATE_HISTOGRAM, ///< UPDATE HISTOGRAM ... is specified after ANALYZE
7272
///< TABLE
73-
DROP_HISTOGRAM ///< DROP HISTOGRAM ... is specified after ANALYZE TABLE
73+
DROP_HISTOGRAM, ///< DROP HISTOGRAM ... is specified after ANALYZE TABLE
74+
QUERY_HISTOGRAM ///< QUERY HISTOGRAM ... is specified after ANALYZE TABLE
7475
};
7576

7677
/**

sql/sql_yacc.yy

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9606,6 +9606,15 @@ opt_histogram:
96069606
if ($$.param == nullptr)
96079607
MYSQL_YYABORT; // OOM
96089608
}
9609+
| QUERY_SYM HISTOGRAM_SYM ON_SYM ident_string_list opt_histogram_update_param
9610+
{
9611+
$$.command=
9612+
Sql_cmd_analyze_table::Histogram_command::QUERY_HISTOGRAM;
9613+
$$.columns= $4;
9614+
$$.param= NEW_PTN YYSTYPE::Histogram_param($5);
9615+
if ($$.param == nullptr)
9616+
MYSQL_YYABORT; // OOM
9617+
}
96099618
| DROP HISTOGRAM_SYM ON_SYM ident_string_list
96109619
{
96119620
$$.command=

0 commit comments

Comments
 (0)