1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

MWL#182: Explain running statements

- Implement new approach to testing (the DBUG_EXECUTE_IF variant)
- add an 'evalp' mysqltest command that is like 'eval' except that
  it prints the original query.
- Fix select_describe() not to change join_tab[i]->type
- More tests
This commit is contained in:
Sergey Petrunya
2011-09-24 21:56:42 +04:00
parent d9045bce1d
commit 203bbfe569
7 changed files with 141 additions and 53 deletions

View File

@ -75,6 +75,8 @@
#define QUERY_SEND_FLAG 1
#define QUERY_REAP_FLAG 2
#define QUERY_PRINT_ORIGINAL_FLAG 4
#ifndef HAVE_SETENV
static int setenv(const char *name, const char *value, int overwrite);
#endif
@ -289,6 +291,7 @@ enum enum_commands {
Q_SEND, Q_REAP,
Q_DIRTY_CLOSE, Q_REPLACE, Q_REPLACE_COLUMN,
Q_PING, Q_EVAL,
Q_EVALP,
Q_RPL_PROBE, Q_ENABLE_RPL_PARSE,
Q_DISABLE_RPL_PARSE, Q_EVAL_RESULT,
Q_ENABLE_QUERY_LOG, Q_DISABLE_QUERY_LOG,
@ -353,6 +356,7 @@ const char *command_names[]=
"replace_column",
"ping",
"eval",
"evalp",
"rpl_probe",
"enable_rpl_parse",
"disable_rpl_parse",
@ -7532,7 +7536,8 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags)
/*
Evaluate query if this is an eval command
*/
if (command->type == Q_EVAL || command->type == Q_SEND_EVAL)
if (command->type == Q_EVAL || command->type == Q_SEND_EVAL ||
command->type == Q_EVALP)
{
init_dynamic_string(&eval_query, "", command->query_len+256, 1024);
do_eval(&eval_query, command->query, command->end, FALSE);
@ -7564,11 +7569,21 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags)
*/
if (!disable_query_log && (flags & QUERY_SEND_FLAG))
{
replace_dynstr_append_mem(ds, query, query_len);
char *print_query= query;
int print_len= query_len;
if (flags & QUERY_PRINT_ORIGINAL_FLAG)
{
print_query= command->query;
print_len= command->end - command->query;
}
replace_dynstr_append_mem(ds, print_query, print_len);
dynstr_append_mem(ds, delimiter, delimiter_length);
dynstr_append_mem(ds, "\n", 1);
}
/* We're done with this flag */
flags &= ~QUERY_PRINT_ORIGINAL_FLAG;
/*
Write the command to the result file before we execute the query
This is needed to be able to analyse the log if something goes
@ -8420,6 +8435,7 @@ int main(int argc, char **argv)
case Q_EVAL_RESULT:
die("'eval_result' command is deprecated");
case Q_EVAL:
case Q_EVALP:
case Q_QUERY_VERTICAL:
case Q_QUERY_HORIZONTAL:
if (command->query == command->query_buf)
@ -8447,6 +8463,9 @@ int main(int argc, char **argv)
flags= QUERY_REAP_FLAG;
}
if (command->type == Q_EVALP)
flags |= QUERY_PRINT_ORIGINAL_FLAG;
/* Check for special property for this query */
display_result_vertically|= (command->type == Q_QUERY_VERTICAL);

View File

@ -3,24 +3,37 @@ create table t0 (a int);
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t1 (a int);
insert into t1 select A.a + 10*B.a + 100*C.a from t0 A, t0 B, t0 C;
alter table t1 add b int, add c int, add filler char(32);
update t1 set b=a, c=a, filler='fooo';
alter table t1 add key(a), add key(b);
show explain for 2*1000*1000*1000;
ERROR HY000: Unknown thread id: 2000000000
SHOW explain for thr2
show explain for (select max(a) from t0);
ERROR 42000: This version of MySQL doesn't yet support 'Usage of subqueries or stored function calls as part of this statement'
show explain for $thr2;
ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command
SHOW explain for thr1
show explain for $thr1;
ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command
select get_lock('optimizer_done', 10);
get_lock('optimizer_done', 10)
1
select count(*) from t1 where a < 100000 and sleep(a*0 + release_lock('optimizer_done') +1);
select get_lock('optimizer_done', 100);
get_lock('optimizer_done', 100)
1
SHOW explain for thr2
set debug='d,show_explain_probe_1';
select count(*) from t1 where a < 100000;
show explain for $thr2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 1000 Using where
select release_lock('optimizer_done');
release_lock('optimizer_done')
1
kill query thr2
1 SIMPLE t1 index a a 5 NULL 1000 Using where; Using index
count(*)
1000
set debug='d,show_explain_probe_1';
select max(c) from t1 where a < 10;
show explain for $thr2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range a a 5 NULL 10 Using where
max(c)
9
set optimizer_switch='index_condition_pushdown=on,mrr=on,mrr_sort_keys=on';
set debug='d,show_explain_probe_1';
explain select max(c) from t1 where a < 10;
show explain for $thr2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range a a 5 NULL 10 Using index condition; Rowid-ordered scan
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range a a 5 NULL 10 Using index condition; Rowid-ordered scan
drop table t0,t1;

View File

@ -9,6 +9,9 @@ create table t0 (a int);
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t1 (a int);
insert into t1 select A.a + 10*B.a + 100*C.a from t0 A, t0 B, t0 C;
alter table t1 add b int, add c int, add filler char(32);
update t1 set b=a, c=a, filler='fooo';
alter table t1 add key(a), add key(b);
#
# Try killing a non-existent thread
@ -16,7 +19,12 @@ insert into t1 select A.a + 10*B.a + 100*C.a from t0 A, t0 B, t0 C;
--error ER_NO_SUCH_THREAD
show explain for 2*1000*1000*1000;
--error ER_NOT_SUPPORTED_YET
show explain for (select max(a) from t0);
#
# Setup two threads and their ids
#
let $thr1=`select connection_id()`;
connect (con1, localhost, root,,);
connection con1;
@ -24,36 +32,47 @@ let $thr2=`select connection_id()`;
connection default;
# SHOW EXPLAIN FOR <idle thread>
echo SHOW explain for thr2;
--disable_query_log
--error ER_ERROR_WHEN_EXECUTING_COMMAND
eval show explain for $thr2;
--enable_query_log
evalp show explain for $thr2;
# SHOW EXPLAIN FOR <ourselves>
echo SHOW explain for thr1;
--disable_query_log
--error ER_ERROR_WHEN_EXECUTING_COMMAND
eval show explain for $thr1;
--enable_query_log
evalp show explain for $thr1;
# SHOW EXPLAIN FOR <running thread>
let $wait_condition= select State='show_explain_trap' from information_schema.processlist where id=$thr2;
#
# Test SHOW EXPLAIN for simple queries
#
connection con1;
select get_lock('optimizer_done', 10);
send select count(*) from t1 where a < 100000 and sleep(a*0 + release_lock('optimizer_done') +1);
connection default;
select get_lock('optimizer_done', 100);
echo SHOW explain for thr2;
--disable_query_log
eval show explain for $thr2;
--enable_query_log
select release_lock('optimizer_done');
--disable_query_log
eval kill query $thr2;
--enable_query_log
echo kill query thr2;
set debug='d,show_explain_probe_1';
send select count(*) from t1 where a < 100000;
connection default;
--source include/wait_condition.inc
evalp show explain for $thr2;
connection con1;
reap;
set debug='d,show_explain_probe_1';
send select max(c) from t1 where a < 10;
connection default;
--source include/wait_condition.inc
evalp show explain for $thr2;
connection con1;
reap;
# We can catch EXPLAIN, too.
set optimizer_switch='index_condition_pushdown=on,mrr=on,mrr_sort_keys=on';
set debug='d,show_explain_probe_1';
send explain select max(c) from t1 where a < 10;
connection default;
--source include/wait_condition.inc
evalp show explain for $thr2;
connection con1;
reap;
#insert into t1 values ('one'),('two'),('three');
## TODO: Test this: multiple SHOW EXPLAIN calls in course of running of one select
##

View File

@ -29,6 +29,10 @@ void Apc_target::init()
// todo: should use my_pthread_... functions instead?
DBUG_ASSERT(!enabled);
(void)pthread_mutex_init(&LOCK_apc_queue, MY_MUTEX_INIT_SLOW);
#ifndef DBUG_OFF
n_calls_processed= 0;
#endif
}
@ -217,6 +221,10 @@ void Apc_target::process_apc_requests()
request->func(request->func_arg);
request->what="func called by process_apc_requests";
#ifndef DBUG_OFF
n_calls_processed++;
#endif
pthread_cond_signal(&request->COND_request);
pthread_mutex_unlock(&request->LOCK_request);

View File

@ -62,13 +62,17 @@ public:
bool make_apc_call(apc_func_t func, void *func_arg,
int timeout_sec, bool *timed_out);
#ifndef DBUG_OFF
int n_calls_processed;
//int call_queue_size;
#endif
private:
class Call_request;
int enabled;
Call_request *apc_calls;
pthread_mutex_t LOCK_apc_queue;
//int call_queue_size;
class Call_request
{

View File

@ -2404,6 +2404,10 @@ int rea_create_table(THD *thd, const char *path,
int format_number(uint inputflag,uint max_length,char * pos,uint length,
char * *errpos);
#ifndef DBUG_OFF
void dbug_serve_apcs(THD *thd, int n_calls);
#endif
/* table.cc */
TABLE_SHARE *alloc_table_share(TABLE_LIST *table_list, char *key,
uint key_length);

View File

@ -245,6 +245,25 @@ Item_equal *find_item_equal(COND_EQUAL *cond_equal, Field *field,
JOIN_TAB *first_depth_first_tab(JOIN* join);
JOIN_TAB *next_depth_first_tab(JOIN* join, JOIN_TAB* tab);
#ifndef DBUG_OFF
// psergey:
void dbug_serve_apcs(THD *thd, int n_calls)
{
// TODO how do we signal that we're SHOW-EXPLAIN-READY?
const char *save_proc_info= thd->proc_info;
thd_proc_info(thd, "show_explain_trap");
int n_apcs= thd->apc_target.n_calls_processed + n_calls;
while (thd->apc_target.n_calls_processed < n_apcs)
{
my_sleep(300);
if (thd->check_killed())
break;
}
thd_proc_info(thd, save_proc_info);
}
#endif
/**
This handles SELECT with and without UNION.
*/
@ -2048,6 +2067,8 @@ void JOIN::exec_inner()
int tmp_error;
DBUG_ENTER("JOIN::exec");
DBUG_EXECUTE_IF("show_explain_probe_1", dbug_serve_apcs(thd, 1););
thd_proc_info(thd, "executing");
error= 0;
if (procedure)
@ -20430,7 +20451,6 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly,
}
else if (join->select_lex == join->unit->fake_select_lex)
{
//if (!join->select_lex->type)
if (on_the_fly)
join->select_lex->set_explain_type(on_the_fly); //psergey
/*
@ -20561,6 +20581,7 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly,
join->select_lex->type;
item_list.push_back(new Item_string(stype, strlen(stype), cs));
enum join_type tab_type= tab->type;
if ((tab->type == JT_ALL || tab->type == JT_HASH) &&
tab->select && tab->select->quick)
{
@ -20569,9 +20590,9 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly,
(quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_INTERSECT) ||
(quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT) ||
(quick_type == QUICK_SELECT_I::QS_TYPE_ROR_UNION))
tab->type= tab->type == JT_ALL ? JT_INDEX_MERGE : JT_HASH_INDEX_MERGE;
tab_type= tab->type == JT_ALL ? JT_INDEX_MERGE : JT_HASH_INDEX_MERGE;
else
tab->type= tab->type == JT_ALL ? JT_RANGE : JT_HASH_RANGE;
tab_type= tab->type == JT_ALL ? JT_RANGE : JT_HASH_RANGE;
}
/* table */
@ -20620,8 +20641,8 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly,
#endif
}
/* "type" column */
item_list.push_back(new Item_string(join_type_str[tab->type],
strlen(join_type_str[tab->type]),
item_list.push_back(new Item_string(join_type_str[tab_type],
strlen(join_type_str[tab_type]),
cs));
/* Build "possible_keys" value and add it to item_list */
if (!tab->keys.is_clear_all())
@ -20645,7 +20666,7 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly,
item_list.push_back(item_null);
/* Build "key", "key_len", and "ref" values and add them to item_list */
if (tab->type == JT_NEXT)
if (tab_type == JT_NEXT)
{
key_info= table->key_info+tab->index;
key_len= key_info->key_length;
@ -20674,12 +20695,12 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly,
}
}
}
if (is_hj && tab->type != JT_HASH)
if (is_hj && tab_type != JT_HASH)
{
tmp2.append(':');
tmp3.append(':');
}
if (tab->type == JT_HASH_NEXT)
if (tab_type == JT_HASH_NEXT)
{
register uint length;
key_info= table->key_info+tab->index;
@ -20701,7 +20722,7 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly,
item_list.push_back(new Item_string(tmp3.ptr(),tmp3.length(),cs));
else
item_list.push_back(item_null);
if (key_info && tab->type != JT_NEXT)
if (key_info && tab_type != JT_NEXT)
item_list.push_back(new Item_string(tmp4.ptr(),tmp4.length(),cs));
else
item_list.push_back(item_null);
@ -20754,7 +20775,7 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly,
ha_rows examined_rows;
if (tab->select && tab->select->quick)
examined_rows= tab->select->quick->records;
else if (tab->type == JT_NEXT || tab->type == JT_ALL || is_hj)
else if (tab_type == JT_NEXT || tab_type == JT_ALL || is_hj)
{
if (tab->limit)
examined_rows= tab->limit;
@ -20793,7 +20814,7 @@ int JOIN::print_explain(select_result_sink *result, bool on_the_fly,
/* Build "Extra" field and add it to item_list. */
key_read=table->key_read;
if ((tab->type == JT_NEXT || tab->type == JT_CONST) &&
if ((tab_type == JT_NEXT || tab_type == JT_CONST) &&
table->covering_keys.is_set(tab->index))
key_read=1;
if (quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT &&