Skip to content

Commit c08de06

Browse files
committed
MDEV-406: ANALYZE $stmt: get ANALYZE work for subqueries
- "ANALYZE $stmt" should discard select's output, but it should still evaluate the output columns (otherwise, subqueries in select list are not executed) - SHOW EXPLAIN's code practice of calling JOIN::save_explain_data() after JOIN::exec() is disastrous for ANALYZE, because it resets all counters after the first execution. It is stopped = "Late" test_if_skip_sort_order() calls explicitly update their part of the query plan. = Also, I had to rewrite I_S optimization to actually have optimization and execution stages.
1 parent 581b889 commit c08de06

13 files changed

+738
-455
lines changed

mysql-test/r/analyze_stmt.result

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,17 @@ id select_type table type possible_keys key key_len ref rows r_rows filtered r_f
6161
NULL UNION RESULT <union1,2> ALL NULL NULL NULL NULL NULL 5 NULL NULL
6262
drop table t1;
6363
drop table t0;
64+
#
65+
# Try a subquery.
66+
#
67+
create table t0 (a int, b int);
68+
insert into t0 values
69+
(0,0),(1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9);
70+
create table t1 (a int, b int);
71+
insert into t1 values (1,1),(2,2),(3,3);
72+
# See .test file for the right values of r_rows and r_filtered.
73+
analyze select a, a in (select t0.b from t0 where t0.b+1=t1.b+1) from t1;
74+
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
75+
1 PRIMARY t1 ALL NULL NULL NULL NULL 3 3 100.00 100.00
76+
2 DEPENDENT SUBQUERY t0 ALL NULL NULL NULL NULL 10 3 100.00 33.33 Using where
77+
drop table t0,t1;

mysql-test/r/show_explain.result

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -641,7 +641,7 @@ set debug_dbug='+d,show_explain_probe_join_exec_start';
641641
SHOW INDEX FROM t1;
642642
show explain for $thr2;
643643
id select_type table type possible_keys key key_len ref rows Extra
644-
1 SIMPLE STATISTICS ALL NULL NULL NULL NULL NULL Skip_open_table; Scanned all databases
644+
1 SIMPLE STATISTICS ALL NULL TABLE_SCHEMA,TABLE_NAME NULL NULL NULL Open_full_table; Scanned 0 databases
645645
Warnings:
646646
Note 1003 SHOW INDEX FROM t1
647647
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment

mysql-test/t/analyze_stmt.test

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,29 @@ insert into t1 select a,a from t0;
3434
analyze (select * from t1 A where a<5) union (select * from t1 B where a in (5,6));
3535
analyze (select * from t1 A where a<5) union (select * from t1 B where a in (1,2));
3636
drop table t1;
37-
3837
drop table t0;
38+
39+
--echo #
40+
--echo # Try a subquery.
41+
--echo #
42+
create table t0 (a int, b int);
43+
insert into t0 values
44+
(0,0),(1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9);
45+
46+
create table t1 (a int, b int);
47+
insert into t1 values (1,1),(2,2),(3,3);
48+
49+
#
50+
# t1 t0
51+
# a=1 (0,1) 2 rows
52+
# a=2 (0,1,2) 3 rows
53+
# a=3 (0,1,2,3) 4 rows
54+
#
55+
# TOTAL TOTAL= 9 rows. 3 executions, avg=3 rows.
56+
# WHERE is satisfied for 1 row per query, which gives filtered=33.3
57+
58+
--echo # See .test file for the right values of r_rows and r_filtered.
59+
analyze select a, a in (select t0.b from t0 where t0.b+1=t1.b+1) from t1;
60+
61+
drop table t0,t1;
62+

sql/protocol.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,42 @@ class Protocol_binary :public Protocol
210210
virtual enum enum_protocol_type type() { return PROTOCOL_BINARY; };
211211
};
212212

213+
214+
/*
215+
A helper for "ANALYZE $stmt" which looks a real network procotol but doesn't
216+
write results to the network.
217+
218+
At first glance, class select_send looks like a more appropriate place to
219+
implement the "write nothing" hook. This is not true, because
220+
- we need to evaluate the value of every item, and do it the way
221+
select_send does it (i.e. call item->val_int() or val_real() or...)
222+
- select_send::send_data() has some other code, like telling the storage
223+
engine that the row can be unlocked. We want to keep that also.
224+
as a result, "ANALYZE $stmt" uses a select_send_analyze which still uses
225+
select_send::send_data() & co., and also uses Protocol_discard object.
226+
*/
227+
228+
class Protocol_discard : public Protocol_text
229+
{
230+
public:
231+
Protocol_discard(THD *thd_arg) : Protocol_text(thd_arg) {}
232+
/* The real writing is done only in write() */
233+
virtual bool write() { return 0; }
234+
virtual bool send_result_set_metadata(List<Item> *list, uint flags)
235+
{
236+
// Don't pas Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF flags
237+
return Protocol_text::send_result_set_metadata(list, 0);
238+
}
239+
240+
// send_error is intentionally not overloaded.
241+
virtual bool send_eof(uint server_status, uint statement_warn_count)
242+
{
243+
return 0;
244+
}
245+
246+
};
247+
248+
213249
void send_warning(THD *thd, uint sql_errno, const char *err=0);
214250
bool net_send_error(THD *thd, uint sql_errno, const char *err,
215251
const char* sqlstate);

sql/sql_class.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3959,19 +3959,21 @@ class select_send :public select_result {
39593959
virtual void cleanup();
39603960
};
39613961

3962+
3963+
/*
3964+
We need this class, because select_send::send_eof() will call ::my_eof.
3965+
3966+
See also class Protocol_discard.
3967+
*/
3968+
39623969
class select_send_analyze : public select_send
39633970
{
3964-
bool discard_data;
39653971
bool send_result_set_metadata(List<Item> &list, uint flags) { return 0; }
3966-
/*
3967-
ANALYZE-todo: we should call val_int() (or val_str() or whatever) to
3968-
compute the columns. If we don't, it's not full execution.
3969-
*/
3970-
int send_data(List<Item> &items) { return 0; }
39713972
bool send_eof() { return 0; }
39723973
void abort_result_set() {}
39733974
};
39743975

3976+
39753977
class select_to_file :public select_result_interceptor {
39763978
protected:
39773979
sql_exchange *exchange;

sql/sql_explain.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,13 @@ int Explain_node::print_explain_for_children(Explain_query *query,
345345
}
346346

347347

348+
void Explain_select::replace_table(uint idx, Explain_table_access *new_tab)
349+
{
350+
delete join_tabs[idx];
351+
join_tabs[idx]= new_tab;
352+
}
353+
354+
348355
Explain_select::~Explain_select()
349356
{
350357
if (join_tabs)

sql/sql_explain.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,12 @@ class Explain_select : public Explain_node
129129
join_tabs[n_join_tabs++]= tab;
130130
return false;
131131
}
132+
133+
/*
134+
This is used to save the results of "late" test_if_skip_sort_order() calls
135+
that are made from JOIN::exec
136+
*/
137+
void replace_table(uint idx, Explain_table_access *new_tab);
132138

133139
public:
134140
int select_id;

sql/sql_parse.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5260,10 +5260,13 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
52605260
{
52615261
//psergey-todo: ANALYZE should hook in here...
52625262
select_result *save_result;
5263+
Protocol *save_protocol;
52635264
if (lex->analyze_stmt)
52645265
{
52655266
save_result= result;
52665267
result= new select_send_analyze();
5268+
save_protocol= thd->protocol;
5269+
thd->protocol= new Protocol_discard(thd);
52675270
}
52685271
else
52695272
{
@@ -5280,6 +5283,7 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
52805283
result= save_result;
52815284
if (!result && !(result= new select_send()))
52825285
return 1;
5286+
thd->protocol= save_protocol;
52835287
thd->lex->explain->send_explain(thd);
52845288

52855289
if (result != lex->result)

0 commit comments

Comments
 (0)