Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
MariaDB
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
MariaDB
Commits
ca8aa390
Commit
ca8aa390
authored
Apr 26, 2012
by
Sergey Petrunya
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
MWL#182: Explain running statements
- Code cleanup
parent
8c4fc9ba
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
220 additions
and
47 deletions
+220
-47
mysql-test/r/show_explain.result
mysql-test/r/show_explain.result
+57
-1
mysql-test/t/show_explain.test
mysql-test/t/show_explain.test
+67
-4
sql/my_apc.cc
sql/my_apc.cc
+45
-11
sql/my_apc.h
sql/my_apc.h
+34
-29
sql/sql_class.cc
sql/sql_class.cc
+2
-1
sql/sql_class.h
sql/sql_class.h
+2
-0
sql/sql_lex.cc
sql/sql_lex.cc
+9
-0
sql/sql_show.cc
sql/sql_show.cc
+4
-1
No files found.
mysql-test/r/show_explain.result
View file @
ca8aa390
drop table if exists t0, t1;
drop table if exists t0, t1
, t2
;
create table t0 (a int);
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t1 (a int);
...
...
@@ -125,4 +125,60 @@ id select_type table type possible_keys key key_len ref rows Extra
2 DEPENDENT SUBQUERY b ALL NULL NULL NULL NULL 10 Using where
a (select max(a) from t0 b where b.a+a.a<10)
0 9
# Try to do SHOW EXPLAIN for a query that runs a SET command:
# I've found experimentally that select_id==2 here...
#
set @show_explain_probe_select_id=2;
set debug='d,show_explain_probe_1';
set @foo= (select max(a) from t0 where sin(a) >0);
show explain for $thr2;
ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command
#
# Attempt SHOW EXPLAIN for an UPDATE
#
create table t2 as select a as a, a as dummy from t0 limit 2;
set @show_explain_probe_select_id=2;
set debug='d,show_explain_probe_1';
update t2 set dummy=0 where (select max(a) from t0 where t2.a + t0.a <3) >3 ;
show explain for $thr2;
ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command
show explain for $thr2;
ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command
drop table t2;
#
# Attempt SHOW EXPLAIN for a DELETE
#
create table t2 as select a as a, a as dummy from t0 limit 2;
set @show_explain_probe_select_id=2;
set debug='d,show_explain_probe_1';
delete from t2 where (select max(a) from t0 where t2.a + t0.a <3) >3 ;
show explain for $thr2;
ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command
show explain for $thr2;
ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command
drop table t2;
#
# Multiple SHOW EXPLAIN calls for one select
#
create table t2 as select a as a, a as dummy from t0 limit 3;
set @show_explain_probe_select_id=2;
set debug='d,show_explain_probe_1';
select t2.a, ((select max(a) from t0 where t2.a + t0.a <3) >3) as SUBQ from t2;
show explain for $thr2;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 3
2 DEPENDENT SUBQUERY t0 ALL NULL NULL NULL NULL 10 Using where
show explain for $thr2;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 3
2 DEPENDENT SUBQUERY t0 ALL NULL NULL NULL NULL 10 Using where
show explain for $thr2;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 3
2 DEPENDENT SUBQUERY t0 ALL NULL NULL NULL NULL 10 Using where
a SUBQ
0 0
1 0
2 0
drop table t2;
drop table t0,t1;
mysql-test/t/show_explain.test
View file @
ca8aa390
...
...
@@ -4,7 +4,7 @@
--
source
include
/
have_debug
.
inc
--
disable_warnings
drop
table
if
exists
t0
,
t1
;
drop
table
if
exists
t0
,
t1
,
t2
;
--
enable_warnings
#
...
...
@@ -186,12 +186,75 @@ reap;
# TODO: explain in the parent subuqery when the un-correlated child has been
# run (and have done irreversible cleanups)
# ^^ Is this at all possible after 5.3?
# Maybe, for 5.3 try this:
# - run before/after the parent has invoked child's optimization
# - run after materialization
--
echo
# Try to do SHOW EXPLAIN for a query that runs a SET command:
--
echo
# I've found experimentally that select_id==2 here...
--
echo
#
set
@
show_explain_probe_select_id
=
2
;
set
debug
=
'd,show_explain_probe_1'
;
send
set
@
foo
=
(
select
max
(
a
)
from
t0
where
sin
(
a
)
>
0
);
connection
default
;
--
source
include
/
wait_condition
.
inc
--
error
ER_ERROR_WHEN_EXECUTING_COMMAND
evalp
show
explain
for
$thr2
;
connection
con1
;
reap
;
# TODO: hit JOIN::optimize for non-select commands: UPDATE/DELETE, SET.
--
echo
#
--
echo
# Attempt SHOW EXPLAIN for an UPDATE
--
echo
#
create
table
t2
as
select
a
as
a
,
a
as
dummy
from
t0
limit
2
;
set
@
show_explain_probe_select_id
=
2
;
set
debug
=
'd,show_explain_probe_1'
;
send
update
t2
set
dummy
=
0
where
(
select
max
(
a
)
from
t0
where
t2
.
a
+
t0
.
a
<
3
)
>
3
;
connection
default
;
--
source
include
/
wait_condition
.
inc
--
error
ER_ERROR_WHEN_EXECUTING_COMMAND
evalp
show
explain
for
$thr2
;
--
error
ER_ERROR_WHEN_EXECUTING_COMMAND
evalp
show
explain
for
$thr2
;
connection
con1
;
reap
;
drop
table
t2
;
--
echo
#
--
echo
# Attempt SHOW EXPLAIN for a DELETE
--
echo
#
create
table
t2
as
select
a
as
a
,
a
as
dummy
from
t0
limit
2
;
set
@
show_explain_probe_select_id
=
2
;
set
debug
=
'd,show_explain_probe_1'
;
send
delete
from
t2
where
(
select
max
(
a
)
from
t0
where
t2
.
a
+
t0
.
a
<
3
)
>
3
;
connection
default
;
--
source
include
/
wait_condition
.
inc
--
error
ER_ERROR_WHEN_EXECUTING_COMMAND
evalp
show
explain
for
$thr2
;
--
error
ER_ERROR_WHEN_EXECUTING_COMMAND
evalp
show
explain
for
$thr2
;
connection
con1
;
reap
;
drop
table
t2
;
--
echo
#
--
echo
# Multiple SHOW EXPLAIN calls for one select
--
echo
#
create
table
t2
as
select
a
as
a
,
a
as
dummy
from
t0
limit
3
;
set
@
show_explain_probe_select_id
=
2
;
set
debug
=
'd,show_explain_probe_1'
;
send
select
t2
.
a
,
((
select
max
(
a
)
from
t0
where
t2
.
a
+
t0
.
a
<
3
)
>
3
)
as
SUBQ
from
t2
;
connection
default
;
--
source
include
/
wait_condition
.
inc
evalp
show
explain
for
$thr2
;
evalp
show
explain
for
$thr2
;
evalp
show
explain
for
$thr2
;
connection
con1
;
reap
;
drop
table
t2
;
## TODO: Test this: multiple SHOW EXPLAIN calls in course of running of one select
##
## TODO: Test this: have several SHOW EXPLAIN requests be queued up for a
## thread and served together.
...
...
sql/my_apc.cc
View file @
ca8aa390
...
...
@@ -24,6 +24,14 @@
*/
/*
Initialize the target.
@note
Initialization must be done prior to enabling/disabling the target, or making
any call requests to it.
Initial state after initialization is 'disabled'.
*/
void
Apc_target
::
init
()
{
// todo: should use my_pthread_... functions instead?
...
...
@@ -36,6 +44,9 @@ void Apc_target::init()
}
/*
Destroy the target. The target must be disabled when this call is made.
*/
void
Apc_target
::
destroy
()
{
DBUG_ASSERT
(
!
enabled
);
...
...
@@ -43,6 +54,9 @@ void Apc_target::destroy()
}
/*
Enter ther state where the target is available for serving APC requests
*/
void
Apc_target
::
enable
()
{
pthread_mutex_lock
(
&
LOCK_apc_queue
);
...
...
@@ -51,6 +65,13 @@ void Apc_target::enable()
}
/*
Make the target unavailable for serving APC requests.
@note
This call will serve all requests that were already enqueued
*/
void
Apc_target
::
disable
()
{
bool
process
=
FALSE
;
...
...
@@ -62,6 +83,9 @@ void Apc_target::disable()
process_apc_requests
();
}
/* (internal) Put request into the request list */
void
Apc_target
::
enqueue_request
(
Call_request
*
qe
)
{
//call_queue_size++;
...
...
@@ -81,6 +105,13 @@ void Apc_target::enqueue_request(Call_request *qe)
}
}
/*
(internal) Remove given request from the request queue.
The request is not necessarily first in the queue.
*/
void
Apc_target
::
dequeue_request
(
Call_request
*
qe
)
{
//call_queue_size--;
...
...
@@ -99,8 +130,10 @@ void Apc_target::dequeue_request(Call_request *qe)
/*
Make an apc call in another thread. The caller is responsible so
that we're not calling to ourselves.
Make an APC (Async Procedure Call) in another thread.
The caller is responsible for making sure he's not calling an Apc_target
that is serviced by the same thread it is called from.
psergey-todo: Should waits here be KILLable? (it seems one needs
to use thd->enter_cond() calls to be killable)
...
...
@@ -119,7 +152,7 @@ bool Apc_target::make_apc_call(apc_func_t func, void *func_arg,
Call_request
apc_request
;
apc_request
.
func
=
func
;
apc_request
.
func_arg
=
func_arg
;
apc_request
.
done
=
FALSE
;
apc_request
.
processed
=
FALSE
;
(
void
)
pthread_cond_init
(
&
apc_request
.
COND_request
,
NULL
);
(
void
)
pthread_mutex_init
(
&
apc_request
.
LOCK_request
,
MY_MUTEX_INIT_SLOW
);
pthread_mutex_lock
(
&
apc_request
.
LOCK_request
);
...
...
@@ -133,19 +166,19 @@ bool Apc_target::make_apc_call(apc_func_t func, void *func_arg,
int
wait_res
=
0
;
/* todo: how about processing other errors here? */
while
(
!
apc_request
.
done
&&
(
wait_res
!=
ETIMEDOUT
))
while
(
!
apc_request
.
processed
&&
(
wait_res
!=
ETIMEDOUT
))
{
wait_res
=
pthread_cond_timedwait
(
&
apc_request
.
COND_request
,
&
apc_request
.
LOCK_request
,
&
abstime
);
}
if
(
!
apc_request
.
done
)
if
(
!
apc_request
.
processed
)
{
/*
We timed out
*/
apc_request
.
done
=
TRUE
;
/*
The wait has timed out. Remove the request from the queue
*/
apc_request
.
processed
=
TRUE
;
*
timed_out
=
TRUE
;
pthread_mutex_unlock
(
&
apc_request
.
LOCK_request
);
//psergey-todo: "Whoa rare event" refers to this part, right? put a comment.
pthread_mutex_lock
(
&
LOCK_apc_queue
);
dequeue_request
(
&
apc_request
);
pthread_mutex_unlock
(
&
LOCK_apc_queue
);
...
...
@@ -171,7 +204,8 @@ bool Apc_target::make_apc_call(apc_func_t func, void *func_arg,
/*
Process all APC requests
Process all APC requests.
This should be called periodically by the APC target thread.
*/
void
Apc_target
::
process_apc_requests
()
...
...
@@ -190,7 +224,7 @@ void Apc_target::process_apc_requests()
request
->
what
=
"seen by process_apc_requests"
;
pthread_mutex_lock
(
&
request
->
LOCK_request
);
if
(
request
->
done
)
if
(
request
->
processed
)
{
/*
We can get here when
...
...
@@ -214,7 +248,7 @@ void Apc_target::process_apc_requests()
*/
request
->
what
=
"dequeued by process_apc_requests"
;
dequeue_request
(
request
);
request
->
done
=
TRUE
;
request
->
processed
=
TRUE
;
pthread_mutex_unlock
(
&
LOCK_apc_queue
);
...
...
sql/my_apc.h
View file @
ca8aa390
...
...
@@ -3,9 +3,18 @@
*/
/*
Design
- Mutex-guarded request queue (it belongs to the target), which can be enabled/
disabled (when empty).
Interface
~~~~~~~~~
(
- This is an APC request queue
- We assume there is a particular owner thread which periodically calls
process_apc_requests() to serve the call requests.
- Other threads can post call requests, and block until they are exectued.
)
Implementation
~~~~~~~~~~~~~~
- The target has a mutex-guarded request queue.
- After the request has been put into queue, the requestor waits for request
to be satisfied. The worker satisifes the request and signals the
...
...
@@ -21,31 +30,11 @@ class Apc_target
Apc_target
()
:
enabled
(
0
),
apc_calls
(
NULL
)
/*, call_queue_size(0)*/
{}
~
Apc_target
()
{
DBUG_ASSERT
(
!
enabled
&&
!
apc_calls
);}
/*
Initialize the target. This must be called before anything else. Right
after initialization, the target is disabled.
*/
void
init
();
/*
Destroy the target. The target must be disabled when this call is made.
*/
void
destroy
();
/*
Enter into state where this target will be serving APC requests
*/
void
enable
();
/*
Leave the state where we could serve APC requests (will serve all already
enqueued requests)
*/
void
disable
();
/*
This should be called periodically to serve observation requests.
*/
void
process_apc_requests
();
typedef
void
(
*
apc_func_t
)(
void
*
arg
);
...
...
@@ -68,18 +57,32 @@ class Apc_target
#endif
private:
class
Call_request
;
/*
Non-zero value means we're enabled. It's an int, not bool, because one can
call enable() N times (and then needs to call disable() N times before the
target is really disabled)
*/
int
enabled
;
/*
Circular, double-linked list of all enqueued call requests.
We use this structure, because we
- process requests sequentially
- a thread that has posted a request may time out (or be KILLed) and
cancel the request, which means we'll need to remove its request at
arbitrary point in time.
*/
Call_request
*
apc_calls
;
pthread_mutex_t
LOCK_apc_queue
;
pthread_mutex_t
LOCK_apc_queue
;
class
Call_request
{
public:
apc_func_t
func
;
void
*
func_arg
;
bool
done
;
apc_func_t
func
;
/* Function to call */
void
*
func_arg
;
/* Argument to pass it */
bool
processed
;
pthread_mutex_t
LOCK_request
;
pthread_cond_t
COND_request
;
...
...
@@ -87,13 +90,15 @@ class Apc_target
Call_request
*
next
;
Call_request
*
prev
;
const
char
*
what
;
const
char
*
what
;
/* State of the request */
};
void
enqueue_request
(
Call_request
*
qe
);
void
dequeue_request
(
Call_request
*
qe
);
/* return the first call request in queue, or NULL if there are none enqueued */
Call_request
*
get_first_in_queue
()
{
{
return
apc_calls
;
}
};
...
...
sql/sql_class.cc
View file @
ca8aa390
...
...
@@ -3033,7 +3033,8 @@ void Show_explain_request::get_explain_data(void *arg)
req
->
target_thd
->
set_n_backup_active_arena
((
Query_arena
*
)
req
->
request_thd
,
&
backup_arena
);
req
->
target_thd
->
lex
->
unit
.
print_explain
(
req
->
explain_buf
);
if
(
req
->
target_thd
->
lex
->
unit
.
print_explain
(
req
->
explain_buf
))
req
->
failed_to_produce
=
TRUE
;
req
->
target_thd
->
restore_active_arena
((
Query_arena
*
)
req
->
request_thd
,
&
backup_arena
);
...
...
sql/sql_class.h
View file @
ca8aa390
...
...
@@ -1467,6 +1467,8 @@ class Show_explain_request
THD
*
target_thd
;
THD
*
request_thd
;
bool
failed_to_produce
;
select_result_explain_buffer
*
explain_buf
;
static
void
get_explain_data
(
void
*
arg
);
...
...
sql/sql_lex.cc
View file @
ca8aa390
...
...
@@ -3792,6 +3792,15 @@ int st_select_lex_unit::print_explain(select_result_sink *output)
{
int
res
=
0
;
SELECT_LEX
*
first
=
first_select
();
if
(
first
&&
!
first
->
next_select
()
&&
!
first
->
join
)
{
/*
If there is only one child, 'first', and it has join==NULL, emit "not in
EXPLAIN state" error.
*/
return
1
;
}
for
(
SELECT_LEX
*
sl
=
first
;
sl
;
sl
=
sl
->
next_select
())
{
...
...
sql/sql_show.cc
View file @
ca8aa390
...
...
@@ -2112,16 +2112,19 @@ void mysqld_show_explain(THD *thd, ulong thread_id)
explain_req
.
explain_buf
=
explain_buf
;
explain_req
.
target_thd
=
tmp
;
explain_req
.
request_thd
=
thd
;
explain_req
.
failed_to_produce
=
FALSE
;
bres
=
tmp
->
apc_target
.
make_apc_call
(
Show_explain_request
::
get_explain_data
,
(
void
*
)
&
explain_req
,
timeout_sec
,
&
timed_out
);
if
(
bres
)
if
(
bres
||
explain_req
.
failed_to_produce
)
{
/* TODO not enabled or time out */
my_error
(
ER_ERROR_WHEN_EXECUTING_COMMAND
,
MYF
(
0
),
"SHOW EXPLAIN"
,
"Target is not running EXPLAINable command"
);
bres
=
TRUE
;
}
pthread_mutex_unlock
(
&
tmp
->
LOCK_thd_data
);
if
(
!
bres
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment