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
c6aee27b
Commit
c6aee27b
authored
Mar 25, 2015
by
Oleksandr Byelkin
Committed by
Sergei Petrunia
Jun 30, 2015
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
MDEV-7811: EXPLAIN/ANALYZE FORMAT=JSON should show subquery cache
parent
498a264d
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
401 additions
and
9 deletions
+401
-9
mysql-test/r/subselect_cache.result
mysql-test/r/subselect_cache.result
+234
-0
mysql-test/t/subselect_cache.test
mysql-test/t/subselect_cache.test
+10
-0
sql/item.cc
sql/item.cc
+13
-0
sql/item.h
sql/item.h
+2
-0
sql/item_subselect.cc
sql/item_subselect.cc
+19
-0
sql/item_subselect.h
sql/item_subselect.h
+4
-1
sql/sql_explain.cc
sql/sql_explain.cc
+29
-1
sql/sql_explain.h
sql/sql_explain.h
+11
-5
sql/sql_expression_cache.cc
sql/sql_expression_cache.cc
+14
-1
sql/sql_expression_cache.h
sql/sql_expression_cache.h
+47
-1
sql/sql_lex.cc
sql/sql_lex.cc
+18
-0
No files found.
mysql-test/r/subselect_cache.result
View file @
c6aee27b
...
...
@@ -39,6 +39,240 @@ Handler_read_prev 0
Handler_read_rnd 0
Handler_read_rnd_deleted 0
Handler_read_rnd_next 31
analyze format=json
select a, (select d from t2 where b=c) from t1;
ANALYZE
{
"query_block": {
"select_id": 1,
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"table": {
"table_name": "t1",
"access_type": "ALL",
"r_loops": 1,
"rows": 10,
"r_rows": 10,
"r_total_time_ms": "REPLACED",
"filtered": 100,
"r_filtered": 100
},
"subqueries": [
{
"query_block": {
"select_id": 2,
"r_loops": 4,
"r_total_time_ms": "REPLACED",
"expression_cache": {
"state": "ENABLED",
"r_hit": 6,
"r_miss": 4,
"r_loops": 10,
"r_hit_ratio": 60
},
"table": {
"table_name": "t2",
"access_type": "ALL",
"r_loops": 4,
"rows": 4,
"r_rows": 4,
"r_total_time_ms": "REPLACED",
"filtered": 100,
"r_filtered": 18.75,
"attached_condition": "(t1.b = t2.c)"
}
}
}
]
}
}
analyze format=json
select a, (select d from t2 where b=c), (select d from t2 where b=c union select 1 order by 1 limit 1) from t1;
ANALYZE
{
"query_block": {
"select_id": 1,
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"table": {
"table_name": "t1",
"access_type": "ALL",
"r_loops": 1,
"rows": 10,
"r_rows": 10,
"r_total_time_ms": "REPLACED",
"filtered": 100,
"r_filtered": 100
},
"subqueries": [
{
"query_block": {
"union_result": {
"table_name": "<union3,4>",
"access_type": "ALL",
"r_loops": 4,
"r_rows": 1,
"expression_cache": {
"state": "ENABLED",
"r_hit": 6,
"r_miss": 4,
"r_loops": 10,
"r_hit_ratio": 60
},
"query_specifications": [
{
"query_block": {
"select_id": 3,
"r_loops": 4,
"r_total_time_ms": "REPLACED",
"table": {
"table_name": "t2",
"access_type": "ALL",
"r_loops": 4,
"rows": 4,
"r_rows": 4,
"r_total_time_ms": "REPLACED",
"filtered": 100,
"r_filtered": 18.75,
"attached_condition": "(t1.b = t2.c)"
}
}
},
{
"query_block": {
"select_id": 4,
"table": {
"message": "No tables used"
}
}
}
]
}
}
},
{
"query_block": {
"select_id": 2,
"r_loops": 4,
"r_total_time_ms": "REPLACED",
"expression_cache": {
"state": "ENABLED",
"r_hit": 6,
"r_miss": 4,
"r_loops": 10,
"r_hit_ratio": 60
},
"table": {
"table_name": "t2",
"access_type": "ALL",
"r_loops": 4,
"rows": 4,
"r_rows": 4,
"r_total_time_ms": "REPLACED",
"filtered": 100,
"r_filtered": 18.75,
"attached_condition": "(t1.b = t2.c)"
}
}
}
]
}
}
explain format=json
select a, (select d from t2 where b=c) from t1;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows": 10,
"filtered": 100
},
"subqueries": [
{
"query_block": {
"select_id": 2,
"expression_cache": {
"state": "UNINITIALYZED"
},
"table": {
"table_name": "t2",
"access_type": "ALL",
"rows": 4,
"filtered": 100,
"attached_condition": "(t1.b = t2.c)"
}
}
}
]
}
}
explain format=json
select a, (select d from t2 where b=c), (select d from t2 where b=c union select 1 order by 1 limit 1) from t1;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows": 10,
"filtered": 100
},
"subqueries": [
{
"query_block": {
"union_result": {
"table_name": "<union3,4>",
"access_type": "ALL",
"expression_cache": {
"state": "UNINITIALYZED"
},
"query_specifications": [
{
"query_block": {
"select_id": 3,
"table": {
"table_name": "t2",
"access_type": "ALL",
"rows": 4,
"filtered": 100,
"attached_condition": "(t1.b = t2.c)"
}
}
},
{
"query_block": {
"select_id": 4,
"table": {
"message": "No tables used"
}
}
}
]
}
}
},
{
"query_block": {
"select_id": 2,
"expression_cache": {
"state": "UNINITIALYZED"
},
"table": {
"table_name": "t2",
"access_type": "ALL",
"rows": 4,
"filtered": 100,
"attached_condition": "(t1.b = t2.c)"
}
}
}
]
}
}
set optimizer_switch='subquery_cache=off';
flush status;
select a, (select d from t2 where b=c) from t1;
...
...
mysql-test/t/subselect_cache.test
View file @
c6aee27b
...
...
@@ -24,6 +24,16 @@ select a, (select d from t2 where b=c) from t1;
show
status
like
"subquery_cache%"
;
show
status
like
'%Handler_read%'
;
--
replace_regex
/
"r_total_time_ms"
:
[
0
-
9
]
*
[
.
]
?
[
0
-
9
]
*/
"r_total_time_ms"
:
"REPLACED"
/
analyze
format
=
json
select
a
,
(
select
d
from
t2
where
b
=
c
)
from
t1
;
--
replace_regex
/
"r_total_time_ms"
:
[
0
-
9
]
*
[
.
]
?
[
0
-
9
]
*/
"r_total_time_ms"
:
"REPLACED"
/
analyze
format
=
json
select
a
,
(
select
d
from
t2
where
b
=
c
),
(
select
d
from
t2
where
b
=
c
union
select
1
order
by
1
limit
1
)
from
t1
;
explain
format
=
json
select
a
,
(
select
d
from
t2
where
b
=
c
)
from
t1
;
explain
format
=
json
select
a
,
(
select
d
from
t2
where
b
=
c
),
(
select
d
from
t2
where
b
=
c
union
select
1
order
by
1
limit
1
)
from
t1
;
set
optimizer_switch
=
'subquery_cache=off'
;
flush
status
;
...
...
sql/item.cc
View file @
c6aee27b
...
...
@@ -7554,6 +7554,19 @@ bool Item_cache_wrapper::set_cache(THD *thd)
DBUG_RETURN
(
expr_cache
==
NULL
);
}
Expression_cache_stat
*
Item_cache_wrapper
::
set_stat
(
MEM_ROOT
*
mem_root
)
{
if
(
expr_cache
)
{
Expression_cache_stat
*
stat
=
new
(
mem_root
)
Expression_cache_stat
(
expr_cache
);
if
(
stat
)
((
Expression_cache_tmptable
*
)
expr_cache
)
->
set_stat
(
stat
);
return
stat
;
}
return
NULL
;
}
/**
Check if the current values of the parameters are in the expression cache
...
...
sql/item.h
View file @
c6aee27b
...
...
@@ -3804,6 +3804,7 @@ class Item_direct_ref_to_ident :public Item_direct_ref
class
Item_cache
;
class
Expression_cache
;
class
Expression_cache_stat
;
/**
The objects of this class can store its values in an expression cache.
...
...
@@ -3838,6 +3839,7 @@ class Item_cache_wrapper :public Item_result_field
enum
Type
real_type
()
const
{
return
orig_item
->
type
();
}
bool
set_cache
(
THD
*
thd
);
Expression_cache_stat
*
set_stat
(
MEM_ROOT
*
mem_root
);
bool
fix_fields
(
THD
*
thd
,
Item
**
it
);
void
cleanup
();
...
...
sql/item_subselect.cc
View file @
c6aee27b
...
...
@@ -1201,7 +1201,10 @@ Item* Item_singlerow_subselect::expr_cache_insert_transformer(uchar *thd_arg)
if
(
expr_cache_is_needed
(
thd
)
&&
(
expr_cache
=
set_expr_cache
(
thd
)))
{
set_expr_cache_stat
(
thd
);
DBUG_RETURN
(
expr_cache
);
}
DBUG_RETURN
(
this
);
}
...
...
@@ -1497,7 +1500,10 @@ Item* Item_exists_subselect::expr_cache_insert_transformer(uchar *thd_arg)
if
(
substype
()
==
EXISTS_SUBS
&&
expr_cache_is_needed
(
thd
)
&&
(
expr_cache
=
set_expr_cache
(
thd
)))
{
set_expr_cache_stat
(
thd
);
DBUG_RETURN
(
expr_cache
);
}
DBUG_RETURN
(
this
);
}
...
...
@@ -6556,3 +6562,16 @@ void subselect_table_scan_engine::cleanup()
{
}
void
Item_subselect
::
set_expr_cache_stat
(
THD
*
thd
)
{
if
(
!
expr_cache
)
return
;
Explain_query
*
qw
=
thd
->
lex
->
explain
;
DBUG_ASSERT
(
qw
);
Explain_node
*
node
=
qw
->
get_node
(
unit
->
first_select
()
->
select_number
);
if
(
!
node
)
return
;
DBUG_ASSERT
(
expr_cache
->
type
()
==
Item
::
EXPR_CACHE_ITEM
);
node
->
cache_stat
=
((
Item_cache_wrapper
*
)
expr_cache
)
->
set_stat
(
qw
->
mem_root
);
}
sql/item_subselect.h
View file @
c6aee27b
...
...
@@ -244,7 +244,10 @@ class Item_subselect :public Item_result_field,
bool
limit_index_condition_pushdown_processor
(
uchar
*
opt_arg
)
{
return
TRUE
;
}
}
void
set_expr_cache_stat
(
THD
*
thd
);
friend
class
select_result_interceptor
;
friend
class
Item_in_optimizer
;
...
...
sql/sql_explain.cc
View file @
c6aee27b
...
...
@@ -23,6 +23,7 @@
#include "sql_select.h"
#include "my_json_writer.h"
#include "opt_range.h"
#include "sql_expression_cache.h"
const
char
*
STR_DELETING_ALL_ROWS
=
"Deleting all rows"
;
const
char
*
STR_IMPOSSIBLE_WHERE
=
"Impossible WHERE"
;
...
...
@@ -543,6 +544,7 @@ void Explain_union::print_explain_json(Explain_query *query,
writer
->
add_null
();
}
print_explain_json_cache
(
writer
,
is_analyze
);
writer
->
add_member
(
"query_specifications"
).
start_array
();
for
(
int
i
=
0
;
i
<
(
int
)
union_members
.
elements
();
i
++
)
...
...
@@ -640,6 +642,30 @@ void Explain_node::print_explain_json_for_children(Explain_query *query,
}
void
Explain_node
::
print_explain_json_cache
(
Json_writer
*
writer
,
bool
is_analyze
)
{
if
(
cache_stat
)
{
cache_stat
->
flush_stat
();
writer
->
add_member
(
"expression_cache"
).
start_object
();
writer
->
add_member
(
"state"
).
add_str
(
Expression_cache_stat
::
state_str
[
cache_stat
->
state
]);
if
(
is_analyze
)
{
writer
->
add_member
(
"r_hit"
).
add_ll
(
cache_stat
->
hit
);
writer
->
add_member
(
"r_miss"
).
add_ll
(
cache_stat
->
miss
);
writer
->
add_member
(
"r_loops"
).
add_ll
(
cache_stat
->
hit
+
cache_stat
->
miss
);
writer
->
add_member
(
"r_hit_ratio"
).
add_ll
(((
double
)
cache_stat
->
hit
)
/
((
double
)(
cache_stat
->
hit
+
cache_stat
->
miss
))
*
100.0
);
}
writer
->
end_object
();
}
}
void
Explain_select
::
replace_table
(
uint
idx
,
Explain_table_access
*
new_tab
)
{
delete
join_tabs
[
idx
];
...
...
@@ -757,17 +783,19 @@ void Explain_select::print_explain_json(Explain_query *query,
{
writer
->
add_member
(
"query_block"
).
start_object
();
writer
->
add_member
(
"select_id"
).
add_ll
(
select_id
);
if
(
is_analyze
&&
time_tracker
.
get_loops
())
{
writer
->
add_member
(
"r_loops"
).
add_ll
(
time_tracker
.
get_loops
());
writer
->
add_member
(
"r_total_time_ms"
).
add_double
(
time_tracker
.
get_time_ms
());
}
if
(
exec_const_cond
)
{
writer
->
add_member
(
"const_condition"
);
write_item
(
writer
,
exec_const_cond
);
}
print_explain_json_cache
(
writer
,
is_analyze
);
Filesort_tracker
*
first_table_sort
=
NULL
;
bool
first_table_sort_used
=
false
;
...
...
sql/sql_explain.h
View file @
c6aee27b
...
...
@@ -84,9 +84,10 @@ class Explain_query;
class
Explain_node
:
public
Sql_alloc
{
public:
Explain_node
(
MEM_ROOT
*
root
)
:
connection_type
(
EXPLAIN_NODE_OTHER
),
children
(
root
)
Explain_node
(
MEM_ROOT
*
root
)
:
cache_stat
(
NULL
),
connection_type
(
EXPLAIN_NODE_OTHER
),
children
(
root
)
{}
/* A type specifying what kind of node this is */
enum
explain_node_type
...
...
@@ -106,10 +107,14 @@ class Explain_node : public Sql_alloc
EXPLAIN_NODE_NON_MERGED_SJ
/* aka JTBM semi-join */
};
virtual
enum
explain_node_type
get_type
()
=
0
;
virtual
int
get_select_id
()
=
0
;
/**
expression cache statistics
*/
Expression_cache_stat
*
cache_stat
;
/*
How this node is connected to its parent.
(NOTE: EXPLAIN_NODE_NON_MERGED_SJ is set very late currently)
...
...
@@ -135,6 +140,7 @@ class Explain_node : public Sql_alloc
uint8
explain_flags
,
bool
is_analyze
);
void
print_explain_json_for_children
(
Explain_query
*
query
,
Json_writer
*
writer
,
bool
is_analyze
);
void
print_explain_json_cache
(
Json_writer
*
writer
,
bool
is_analyze
);
virtual
~
Explain_node
(){}
};
...
...
@@ -221,7 +227,7 @@ class Explain_select : public Explain_basic_join
members have no info
*/
const
char
*
message
;
/* Expensive constant condition */
Item
*
exec_const_cond
;
...
...
sql/sql_expression_cache.cc
View file @
c6aee27b
...
...
@@ -43,7 +43,7 @@ ulong subquery_cache_miss, subquery_cache_hit;
Expression_cache_tmptable
::
Expression_cache_tmptable
(
THD
*
thd
,
List
<
Item
>
&
dependants
,
Item
*
value
)
:
cache_table
(
NULL
),
table_thd
(
thd
),
items
(
dependants
),
val
(
value
),
:
cache_table
(
NULL
),
table_thd
(
thd
),
stat
(
NULL
),
items
(
dependants
),
val
(
value
),
hit
(
0
),
miss
(
0
),
inited
(
0
)
{
DBUG_ENTER
(
"Expression_cache_tmptable::Expression_cache_tmptable"
);
...
...
@@ -61,6 +61,9 @@ void Expression_cache_tmptable::disable_cache()
cache_table
->
file
->
ha_index_end
();
free_tmp_table
(
table_thd
,
cache_table
);
cache_table
=
NULL
;
flush_stat
();
if
(
stat
)
stat
->
cache
=
NULL
;
}
...
...
@@ -164,6 +167,7 @@ void Expression_cache_tmptable::init()
goto
error
;
}
flush_stat
();
DBUG_VOID_RETURN
;
error:
...
...
@@ -180,6 +184,11 @@ Expression_cache_tmptable::~Expression_cache_tmptable()
if
(
cache_table
)
disable_cache
();
else
{
flush_stat
();
stat
=
NULL
;
}
}
...
...
@@ -323,3 +332,7 @@ void Expression_cache_tmptable::print(String *str, enum_query_type query_type)
}
str
->
append
(
'>'
);
}
const
char
*
Expression_cache_stat
::
state_str
[
3
]
=
{
"UNINITIALYZED"
,
"DISABLED"
,
"ENABLED"
};
sql/sql_expression_cache.h
View file @
c6aee27b
...
...
@@ -19,6 +19,7 @@
#include "sql_select.h"
/**
Interface for expression cache
...
...
@@ -62,6 +63,11 @@ class Expression_cache :public Sql_alloc
Initialize this cache
*/
virtual
void
init
()
=
0
;
/**
Save this object's statistics into Expression_cache_stat object
*/
virtual
void
flush_stat
()
=
0
;
};
struct
st_table_ref
;
...
...
@@ -69,6 +75,30 @@ struct st_join_table;
class
Item_field
;
class
Expression_cache_stat
:
public
Sql_alloc
{
public:
enum
expr_cache_state
{
UNINITED
,
STOPPED
,
OK
};
Expression_cache_stat
(
Expression_cache
*
c
)
:
cache
(
c
),
hit
(
0
),
miss
(
0
),
state
(
UNINITED
)
{}
Expression_cache
*
cache
;
ulong
hit
,
miss
;
enum
expr_cache_state
state
;
static
const
char
*
state_str
[
3
];
void
set
(
ulong
h
,
ulong
m
,
enum
expr_cache_state
s
)
{
hit
=
h
;
miss
=
m
;
state
=
s
;}
void
flush_stat
()
{
if
(
cache
)
cache
->
flush_stat
();
}
};
/**
Implementation of expression cache over a temporary table
*/
...
...
@@ -85,6 +115,20 @@ class Expression_cache_tmptable :public Expression_cache
bool
is_inited
()
{
return
inited
;
};
void
init
();
void
set_stat
(
Expression_cache_stat
*
st
)
{
stat
=
st
;
flush_stat
();
}
virtual
void
flush_stat
()
{
if
(
stat
)
stat
->
set
(
hit
,
miss
,
(
inited
?
(
cache_table
?
Expression_cache_stat
::
OK
:
Expression_cache_stat
::
STOPPED
)
:
Expression_cache_stat
::
UNINITED
));
}
private:
void
disable_cache
();
...
...
@@ -94,6 +138,8 @@ class Expression_cache_tmptable :public Expression_cache
TABLE
*
cache_table
;
/* Thread handle for the temporary table */
THD
*
table_thd
;
/* EXPALIN/ANALYZE statistics */
Expression_cache_stat
*
stat
;
/* TABLE_REF for index lookup */
struct
st_table_ref
ref
;
/* Cached result */
...
...
@@ -103,7 +149,7 @@ class Expression_cache_tmptable :public Expression_cache
/* Value Item example */
Item
*
val
;
/* hit/miss counters */
u
int
hit
,
miss
;
u
long
hit
,
miss
;
/* Set on if the object has been succesfully initialized with init() */
bool
inited
;
};
...
...
sql/sql_lex.cc
View file @
c6aee27b
...
...
@@ -3505,6 +3505,8 @@ bool st_select_lex::optimize_unflattened_subqueries(bool const_only)
bool
empty_union_result
=
true
;
bool
is_correlated_unit
=
false
;
bool
first
=
true
;
bool
union_plan_saved
=
false
;
/*
If the subquery is a UNION, optimize all the subqueries in the UNION. If
there is no UNION, then the loop will execute once for the subquery.
...
...
@@ -3512,6 +3514,17 @@ bool st_select_lex::optimize_unflattened_subqueries(bool const_only)
for
(
SELECT_LEX
*
sl
=
un
->
first_select
();
sl
;
sl
=
sl
->
next_select
())
{
JOIN
*
inner_join
=
sl
->
join
;
if
(
first
)
first
=
false
;
else
{
if
(
!
union_plan_saved
)
{
union_plan_saved
=
true
;
if
(
un
->
save_union_explain
(
un
->
thd
->
lex
->
explain
))
return
true
;
/* Failure */
}
}
if
(
!
inner_join
)
continue
;
SELECT_LEX
*
save_select
=
un
->
thd
->
lex
->
current_select
;
...
...
@@ -4365,10 +4378,15 @@ void LEX::restore_set_statement_var()
int
st_select_lex_unit
::
save_union_explain
(
Explain_query
*
output
)
{
SELECT_LEX
*
first
=
first_select
();
if
(
output
->
get_union
(
first
->
select_number
))
return
0
;
/* Already added */
Explain_union
*
eu
=
new
(
output
->
mem_root
)
Explain_union
(
output
->
mem_root
,
thd
->
lex
->
analyze_stmt
);
if
(
derived
)
eu
->
connection_type
=
Explain_node
::
EXPLAIN_NODE_DERIVED
;
/*
...
...
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