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
424d5de8
Commit
424d5de8
authored
Jun 25, 2014
by
Sergei Petrunia
Browse files
Options
Browse Files
Download
Plain Diff
Merge bb-10.1-explain-analyze into 10.1
parents
787ec317
b561a98a
Changes
23
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
1354 additions
and
550 deletions
+1354
-550
mysql-test/r/analyze_stmt.result
mysql-test/r/analyze_stmt.result
+149
-0
mysql-test/r/ps.result
mysql-test/r/ps.result
+1
-0
mysql-test/r/show_explain.result
mysql-test/r/show_explain.result
+1
-1
mysql-test/t/analyze_stmt.test
mysql-test/t/analyze_stmt.test
+109
-0
mysql-test/t/ps.test
mysql-test/t/ps.test
+1
-0
sql/protocol.h
sql/protocol.h
+36
-0
sql/sql_class.cc
sql/sql_class.cc
+18
-1
sql/sql_class.h
sql/sql_class.h
+14
-0
sql/sql_delete.cc
sql/sql_delete.cc
+9
-0
sql/sql_explain.cc
sql/sql_explain.cc
+102
-31
sql/sql_explain.h
sql/sql_explain.h
+94
-12
sql/sql_join_cache.cc
sql/sql_join_cache.cc
+28
-10
sql/sql_join_cache.h
sql/sql_join_cache.h
+4
-4
sql/sql_lex.cc
sql/sql_lex.cc
+3
-2
sql/sql_lex.h
sql/sql_lex.h
+3
-1
sql/sql_parse.cc
sql/sql_parse.cc
+29
-3
sql/sql_select.cc
sql/sql_select.cc
+496
-397
sql/sql_select.h
sql/sql_select.h
+12
-3
sql/sql_show.cc
sql/sql_show.cc
+149
-80
sql/sql_show.h
sql/sql_show.h
+63
-0
sql/sql_update.cc
sql/sql_update.cc
+9
-2
sql/sql_yacc.yy
sql/sql_yacc.yy
+10
-1
sql/table.h
sql/table.h
+14
-2
No files found.
mysql-test/r/analyze_stmt.result
0 → 100644
View file @
424d5de8
drop table if exists t0,t1,t2,t3;
create table t0 (a int) engine=myisam;
INSERT INTO t0 VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t1 (a int) engine=myisam;
INSERT INTO t1 select * from t0;
# Try a few basic selects to see that r_rows and r_filtered columns work
analyze select * from t1;
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 10 10 100.00 100.00
analyze select * from t1 where a<5;
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 10 10 100.00 50.00 Using where
analyze select * from t1 where a>100;
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 10 10 100.00 0.00 Using where
# ANALYZE DELETE will delete rows:
analyze delete from t1 where a in (2,3,4);
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 10 NULL 100.00 30.00 Using where
select * from t1;
a
0
1
5
6
7
8
9
drop table t1;
# ANALYZE UPDATE will make updates:
create table t1(a int, b int);
insert into t1 select a,a from t0;
analyze update t1 set b=100+b where a in (6,7,8);
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 10 NULL 100.00 30.00 Using where
select * from t1;
a b
0 0
1 1
2 2
3 3
4 4
5 5
6 106
7 107
8 108
9 9
drop table t1;
# Check that UNION works
create table t1(a int, b int);
insert into t1 select a,a from t0;
analyze (select * from t1 A where a<5) union (select * from t1 B where a in (5,6));
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
1 PRIMARY A ALL NULL NULL NULL NULL 10 10 100.00 50.00 Using where
2 UNION B ALL NULL NULL NULL NULL 10 10 100.00 20.00 Using where
NULL UNION RESULT <union1,2> ALL NULL NULL NULL NULL NULL 7 NULL NULL
analyze (select * from t1 A where a<5) union (select * from t1 B where a in (1,2));
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
1 PRIMARY A ALL NULL NULL NULL NULL 10 10 100.00 50.00 Using where
2 UNION B ALL NULL NULL NULL NULL 10 10 100.00 20.00 Using where
NULL UNION RESULT <union1,2> ALL NULL NULL NULL NULL NULL 5 NULL NULL
drop table t1;
drop table t0;
#
# Try a subquery.
#
create table t0 (a int, b int);
insert into t0 values
(0,0),(1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9);
create table t1 (a int, b int);
insert into t1 values (1,1),(2,2),(3,3);
# See .test file for the right values of r_rows and r_filtered.
analyze select a, a in (select t0.b from t0 where t0.b+1=t1.b+1) from t1;
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 3 3 100.00 100.00
2 DEPENDENT SUBQUERY t0 ALL NULL NULL NULL NULL 10 3 100.00 33.33 Using where
# Try a subquery that is never executed
analyze select a, a in (select t0.b from t0 where t0.b+1=t1.b+1) from t1 where t1.a > 5;
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 3 3 100.00 0.00 Using where
2 DEPENDENT SUBQUERY t0 ALL NULL NULL NULL NULL 10 NULL 100.00 NULL Using where
drop table t0, t1;
#
# Tests for join buffering
#
create table t0 (a int, b int);
insert into t0 values
(0,0),(1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9);
create table t1 like t0;
insert into t1 select * from t0;
explain select * from t0, t1 where t0.a<5 and t1.a<5;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t0 ALL NULL NULL NULL NULL 10 Using where
1 SIMPLE t1 ALL NULL NULL NULL NULL 10 Using where; Using join buffer (flat, BNL join)
# These should have filtered=50
analyze select * from t0, t1 where t0.a<5 and t1.a<5;
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
1 SIMPLE t0 ALL NULL NULL NULL NULL 10 10 100.00 50.00 Using where
1 SIMPLE t1 ALL NULL NULL NULL NULL 10 10 100.00 50.00 Using where; Using join buffer (flat, BNL join)
explain select * from t0, t1 where t0.a<5 and t1.b=t0.b;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t0 ALL NULL NULL NULL NULL 10 Using where
1 SIMPLE t1 ALL NULL NULL NULL NULL 10 Using where; Using join buffer (flat, BNL join)
# Now, t1 should have filtered=10
analyze select * from t0, t1 where t0.a<5 and t1.b=t0.b;
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
1 SIMPLE t0 ALL NULL NULL NULL NULL 10 10 100.00 50.00 Using where
1 SIMPLE t1 ALL NULL NULL NULL NULL 10 10 100.00 10.00 Using where; Using join buffer (flat, BNL join)
explain select * from t0, t1 where t0.a<5 and t1.a<5 and t1.b=t0.b;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t0 ALL NULL NULL NULL NULL 10 Using where
1 SIMPLE t1 ALL NULL NULL NULL NULL 10 Using where; Using join buffer (flat, BNL join)
# Now, t1 should have filtered=10
analyze select * from t0, t1 where t0.a<5 and t1.a<5 and t1.b=t0.b;
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
1 SIMPLE t0 ALL NULL NULL NULL NULL 10 10 100.00 50.00 Using where
1 SIMPLE t1 ALL NULL NULL NULL NULL 10 10 100.00 10.00 Using where; Using join buffer (flat, BNL join)
# TODO: Check what is counted for "range checked for each record".
#
# Test for joins
#
create table t2 (key1 int, key2x int, col1 int, key(key1), key(key2x));
insert into t2 select A.a + 10 *B.a +100 * C.a,
(A.a + 10 *B.a +100 * C.a)*2,
A.a + 10 *B.a +100 * C.a
from t0 A, t0 B, t0 C;
# This always has matches, filtered=100%.
analyze select * from t1,t2 where t2.key1=t1.a;
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 10 10 100.00 100.00 Using where
1 SIMPLE t2 ref key1 key1 5 test.t1.a 1 1 100.00 100.00
# This shows r_rows=0. It is actually 0.5 (should r_rows be changed to double?)
analyze select * from t1,t2 where t2.key2x=t1.a;
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 10 10 100.00 100.00 Using where
1 SIMPLE t2 ref key2x key2x 5 test.t1.a 1 0 100.00 100.00
select * from t1,t2 where t2.key2x=t1.a;
a b key1 key2x col1
0 0 0 0 0
2 2 1 2 1
4 4 2 4 2
6 6 3 6 3
8 8 4 8 4
# This has t2.filtered=40% (there are 5 values: {0,1,2,3,4}. two of them have mod=0)
analyze select * from t1,t2 where t2.key2x=t1.a and mod(t2.col1,4)=0;
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 10 10 100.00 100.00 Using where
1 SIMPLE t2 ref key2x key2x 5 test.t1.a 1 0 100.00 40.00 Using where
drop table t0,t1,t2;
mysql-test/r/ps.result
View file @
424d5de8
call mtr.add_suppression('Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT.');
call mtr.add_suppression('Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT.');
drop table if exists t1,t2,t3,t4;
drop table if exists t1,t2,t3,t4;
drop database if exists mysqltest1;
drop database if exists client_test_db;
drop database if exists client_test_db;
create table t1
create table t1
(
(
...
...
mysql-test/r/show_explain.result
View file @
424d5de8
...
@@ -641,7 +641,7 @@ set debug_dbug='+d,show_explain_probe_join_exec_start';
...
@@ -641,7 +641,7 @@ set debug_dbug='+d,show_explain_probe_join_exec_start';
SHOW INDEX FROM t1;
SHOW INDEX FROM t1;
show explain for $thr2;
show explain for $thr2;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE STATISTICS ALL NULL
NULL NULL NULL NULL Skip_open_table; Scanned all
databases
1 SIMPLE STATISTICS ALL NULL
TABLE_SCHEMA,TABLE_NAME NULL NULL NULL Open_full_table; Scanned 0
databases
Warnings:
Warnings:
Note 1003 SHOW INDEX FROM t1
Note 1003 SHOW INDEX FROM t1
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
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
0 → 100644
View file @
424d5de8
#
# Tests for "ANALYZE $statement" feature (PostgreSQL's analog is called EXPLAIN ANALYZE)
#
--
disable_warnings
drop
table
if
exists
t0
,
t1
,
t2
,
t3
;
--
enable_warnings
create
table
t0
(
a
int
)
engine
=
myisam
;
INSERT
INTO
t0
VALUES
(
0
),(
1
),(
2
),(
3
),(
4
),(
5
),(
6
),(
7
),(
8
),(
9
);
create
table
t1
(
a
int
)
engine
=
myisam
;
INSERT
INTO
t1
select
*
from
t0
;
--
echo
# Try a few basic selects to see that r_rows and r_filtered columns work
analyze
select
*
from
t1
;
analyze
select
*
from
t1
where
a
<
5
;
analyze
select
*
from
t1
where
a
>
100
;
--
echo
# ANALYZE DELETE will delete rows:
analyze
delete
from
t1
where
a
in
(
2
,
3
,
4
);
select
*
from
t1
;
drop
table
t1
;
--
echo
# ANALYZE UPDATE will make updates:
create
table
t1
(
a
int
,
b
int
);
insert
into
t1
select
a
,
a
from
t0
;
analyze
update
t1
set
b
=
100
+
b
where
a
in
(
6
,
7
,
8
);
select
*
from
t1
;
drop
table
t1
;
--
echo
# Check that UNION works
create
table
t1
(
a
int
,
b
int
);
insert
into
t1
select
a
,
a
from
t0
;
analyze
(
select
*
from
t1
A
where
a
<
5
)
union
(
select
*
from
t1
B
where
a
in
(
5
,
6
));
analyze
(
select
*
from
t1
A
where
a
<
5
)
union
(
select
*
from
t1
B
where
a
in
(
1
,
2
));
drop
table
t1
;
drop
table
t0
;
--
echo
#
--
echo
# Try a subquery.
--
echo
#
create
table
t0
(
a
int
,
b
int
);
insert
into
t0
values
(
0
,
0
),(
1
,
1
),(
2
,
2
),(
3
,
3
),(
4
,
4
),(
5
,
5
),(
6
,
6
),(
7
,
7
),(
8
,
8
),(
9
,
9
);
create
table
t1
(
a
int
,
b
int
);
insert
into
t1
values
(
1
,
1
),(
2
,
2
),(
3
,
3
);
#
# t1 t0
# a=1 (0,1) 2 rows
# a=2 (0,1,2) 3 rows
# a=3 (0,1,2,3) 4 rows
#
# TOTAL TOTAL= 9 rows. 3 executions, avg=3 rows.
# WHERE is satisfied for 1 row per query, which gives filtered=33.3
--
echo
# See .test file for the right values of r_rows and r_filtered.
analyze
select
a
,
a
in
(
select
t0
.
b
from
t0
where
t0
.
b
+
1
=
t1
.
b
+
1
)
from
t1
;
--
echo
# Try a subquery that is never executed
analyze
select
a
,
a
in
(
select
t0
.
b
from
t0
where
t0
.
b
+
1
=
t1
.
b
+
1
)
from
t1
where
t1
.
a
>
5
;
drop
table
t0
,
t1
;
--
echo
#
--
echo
# Tests for join buffering
--
echo
#
create
table
t0
(
a
int
,
b
int
);
insert
into
t0
values
(
0
,
0
),(
1
,
1
),(
2
,
2
),(
3
,
3
),(
4
,
4
),(
5
,
5
),(
6
,
6
),(
7
,
7
),(
8
,
8
),(
9
,
9
);
create
table
t1
like
t0
;
insert
into
t1
select
*
from
t0
;
explain
select
*
from
t0
,
t1
where
t0
.
a
<
5
and
t1
.
a
<
5
;
--
echo
# These should have filtered=50
analyze
select
*
from
t0
,
t1
where
t0
.
a
<
5
and
t1
.
a
<
5
;
explain
select
*
from
t0
,
t1
where
t0
.
a
<
5
and
t1
.
b
=
t0
.
b
;
--
echo
# Now, t1 should have filtered=10
analyze
select
*
from
t0
,
t1
where
t0
.
a
<
5
and
t1
.
b
=
t0
.
b
;
explain
select
*
from
t0
,
t1
where
t0
.
a
<
5
and
t1
.
a
<
5
and
t1
.
b
=
t0
.
b
;
--
echo
# Now, t1 should have filtered=10
analyze
select
*
from
t0
,
t1
where
t0
.
a
<
5
and
t1
.
a
<
5
and
t1
.
b
=
t0
.
b
;
--
echo
# TODO: Check what is counted for "range checked for each record".
--
echo
#
--
echo
# Test for joins
--
echo
#
create
table
t2
(
key1
int
,
key2x
int
,
col1
int
,
key
(
key1
),
key
(
key2x
));
insert
into
t2
select
A
.
a
+
10
*
B
.
a
+
100
*
C
.
a
,
(
A
.
a
+
10
*
B
.
a
+
100
*
C
.
a
)
*
2
,
A
.
a
+
10
*
B
.
a
+
100
*
C
.
a
from
t0
A
,
t0
B
,
t0
C
;
--
echo
# This always has matches, filtered=100%.
analyze
select
*
from
t1
,
t2
where
t2
.
key1
=
t1
.
a
;
--
echo
# This shows r_rows=0. It is actually 0.5 (should r_rows be changed to double?)
analyze
select
*
from
t1
,
t2
where
t2
.
key2x
=
t1
.
a
;
select
*
from
t1
,
t2
where
t2
.
key2x
=
t1
.
a
;
--
echo
# This has t2.filtered=40% (there are 5 values: {0,1,2,3,4}. two of them have mod=0)
analyze
select
*
from
t1
,
t2
where
t2
.
key2x
=
t1
.
a
and
mod
(
t2
.
col1
,
4
)
=
0
;
drop
table
t0
,
t1
,
t2
;
mysql-test/t/ps.test
View file @
424d5de8
...
@@ -7,6 +7,7 @@ call mtr.add_suppression('Unsafe statement written to the binary log using state
...
@@ -7,6 +7,7 @@ call mtr.add_suppression('Unsafe statement written to the binary log using state
--
disable_warnings
--
disable_warnings
drop
table
if
exists
t1
,
t2
,
t3
,
t4
;
drop
table
if
exists
t1
,
t2
,
t3
,
t4
;
drop
database
if
exists
mysqltest1
;
# Avoid wrong warnings if mysql_client_test fails
# Avoid wrong warnings if mysql_client_test fails
drop
database
if
exists
client_test_db
;
drop
database
if
exists
client_test_db
;
--
enable_warnings
--
enable_warnings
...
...
sql/protocol.h
View file @
424d5de8
...
@@ -210,6 +210,42 @@ class Protocol_binary :public Protocol
...
@@ -210,6 +210,42 @@ class Protocol_binary :public Protocol
virtual
enum
enum_protocol_type
type
()
{
return
PROTOCOL_BINARY
;
};
virtual
enum
enum_protocol_type
type
()
{
return
PROTOCOL_BINARY
;
};
};
};
/*
A helper for "ANALYZE $stmt" which looks a real network procotol but doesn't
write results to the network.
At first glance, class select_send looks like a more appropriate place to
implement the "write nothing" hook. This is not true, because
- we need to evaluate the value of every item, and do it the way
select_send does it (i.e. call item->val_int() or val_real() or...)
- select_send::send_data() has some other code, like telling the storage
engine that the row can be unlocked. We want to keep that also.
as a result, "ANALYZE $stmt" uses a select_send_analyze which still uses
select_send::send_data() & co., and also uses Protocol_discard object.
*/
class
Protocol_discard
:
public
Protocol_text
{
public:
Protocol_discard
(
THD
*
thd_arg
)
:
Protocol_text
(
thd_arg
)
{}
/* The real writing is done only in write() */
virtual
bool
write
()
{
return
0
;
}
virtual
bool
send_result_set_metadata
(
List
<
Item
>
*
list
,
uint
flags
)
{
// Don't pas Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF flags
return
Protocol_text
::
send_result_set_metadata
(
list
,
0
);
}
// send_error is intentionally not overloaded.
virtual
bool
send_eof
(
uint
server_status
,
uint
statement_warn_count
)
{
return
0
;
}
};
void
send_warning
(
THD
*
thd
,
uint
sql_errno
,
const
char
*
err
=
0
);
void
send_warning
(
THD
*
thd
,
uint
sql_errno
,
const
char
*
err
=
0
);
bool
net_send_error
(
THD
*
thd
,
uint
sql_errno
,
const
char
*
err
,
bool
net_send_error
(
THD
*
thd
,
uint
sql_errno
,
const
char
*
err
,
const
char
*
sqlstate
);
const
char
*
sqlstate
);
...
...
sql/sql_class.cc
View file @
424d5de8
...
@@ -2282,6 +2282,9 @@ int THD::send_explain_fields(select_result *result)
...
@@ -2282,6 +2282,9 @@ int THD::send_explain_fields(select_result *result)
/*
/*
Populate the provided field_list with EXPLAIN output columns.
Populate the provided field_list with EXPLAIN output columns.
this->lex->describe has the EXPLAIN flags
this->lex->describe has the EXPLAIN flags
The set/order of columns must be kept in sync with
Explain_query::print_explain and co.
*/
*/
void
THD
::
make_explain_field_list
(
List
<
Item
>
&
field_list
)
void
THD
::
make_explain_field_list
(
List
<
Item
>
&
field_list
)
...
@@ -2317,11 +2320,25 @@ void THD::make_explain_field_list(List<Item> &field_list)
...
@@ -2317,11 +2320,25 @@ void THD::make_explain_field_list(List<Item> &field_list)
item
->
maybe_null
=
1
;
item
->
maybe_null
=
1
;
field_list
.
push_back
(
item
=
new
Item_return_int
(
"rows"
,
10
,
field_list
.
push_back
(
item
=
new
Item_return_int
(
"rows"
,
10
,
MYSQL_TYPE_LONGLONG
));
MYSQL_TYPE_LONGLONG
));
if
(
lex
->
describe
&
DESCRIBE_EXTENDED
)
if
(
lex
->
analyze_stmt
)
{
field_list
.
push_back
(
item
=
new
Item_return_int
(
"r_rows"
,
10
,
MYSQL_TYPE_LONGLONG
));
item
->
maybe_null
=
1
;
}
if
(
lex
->
analyze_stmt
||
lex
->
describe
&
DESCRIBE_EXTENDED
)
{
{
field_list
.
push_back
(
item
=
new
Item_float
(
"filtered"
,
0.1234
,
2
,
4
));
field_list
.
push_back
(
item
=
new
Item_float
(
"filtered"
,
0.1234
,
2
,
4
));
item
->
maybe_null
=
1
;
item
->
maybe_null
=
1
;
}
}
if
(
lex
->
analyze_stmt
)
{
field_list
.
push_back
(
item
=
new
Item_float
(
"r_filtered"
,
0.1234
,
2
,
4
));
item
->
maybe_null
=
1
;
}
item
->
maybe_null
=
1
;
item
->
maybe_null
=
1
;
field_list
.
push_back
(
new
Item_empty_string
(
"Extra"
,
255
,
cs
));
field_list
.
push_back
(
new
Item_empty_string
(
"Extra"
,
255
,
cs
));
}
}
...
...
sql/sql_class.h
View file @
424d5de8
...
@@ -3961,6 +3961,20 @@ class select_send :public select_result {
...
@@ -3961,6 +3961,20 @@ class select_send :public select_result {
};
};
/*
We need this class, because select_send::send_eof() will call ::my_eof.
See also class Protocol_discard.
*/
class
select_send_analyze
:
public
select_send
{
bool
send_result_set_metadata
(
List
<
Item
>
&
list
,
uint
flags
)
{
return
0
;
}
bool
send_eof
()
{
return
0
;
}
void
abort_result_set
()
{}
};
class
select_to_file
:
public
select_result_interceptor
{
class
select_to_file
:
public
select_result_interceptor
{
protected:
protected:
sql_exchange
*
exchange
;
sql_exchange
*
exchange
;
...
...
sql/sql_delete.cc
View file @
424d5de8
...
@@ -223,6 +223,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
...
@@ -223,6 +223,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
killed_state
killed_status
=
NOT_KILLED
;
killed_state
killed_status
=
NOT_KILLED
;
THD
::
enum_binlog_query_type
query_type
=
THD
::
ROW_QUERY_TYPE
;
THD
::
enum_binlog_query_type
query_type
=
THD
::
ROW_QUERY_TYPE
;
bool
with_select
=
!
select_lex
->
item_list
.
is_empty
();
bool
with_select
=
!
select_lex
->
item_list
.
is_empty
();
Explain_delete
*
explain
;
Delete_plan
query_plan
(
thd
->
mem_root
);
Delete_plan
query_plan
(
thd
->
mem_root
);
query_plan
.
index
=
MAX_KEY
;
query_plan
.
index
=
MAX_KEY
;
query_plan
.
using_filesort
=
FALSE
;
query_plan
.
using_filesort
=
FALSE
;
...
@@ -538,9 +539,11 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
...
@@ -538,9 +539,11 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
goto
cleanup
;
goto
cleanup
;
}
}
explain
=
(
Explain_delete
*
)
thd
->
lex
->
explain
->
get_upd_del_plan
();
while
(
!
(
error
=
info
.
read_record
(
&
info
))
&&
!
thd
->
killed
&&
while
(
!
(
error
=
info
.
read_record
(
&
info
))
&&
!
thd
->
killed
&&
!
thd
->
is_error
())
!
thd
->
is_error
())
{
{
explain
->
on_record_read
();
if
(
table
->
vfield
)
if
(
table
->
vfield
)
update_virtual_fields
(
thd
,
table
,
update_virtual_fields
(
thd
,
table
,
table
->
triggers
?
VCOL_UPDATE_ALL
:
table
->
triggers
?
VCOL_UPDATE_ALL
:
...
@@ -549,6 +552,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
...
@@ -549,6 +552,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
// thd->is_error() is tested to disallow delete row on error
// thd->is_error() is tested to disallow delete row on error
if
(
!
select
||
select
->
skip_record
(
thd
)
>
0
)
if
(
!
select
||
select
->
skip_record
(
thd
)
>
0
)
{
{
explain
->
on_record_after_where
();
if
(
table
->
triggers
&&
if
(
table
->
triggers
&&
table
->
triggers
->
process_triggers
(
thd
,
TRG_EVENT_DELETE
,
table
->
triggers
->
process_triggers
(
thd
,
TRG_EVENT_DELETE
,
TRG_ACTION_BEFORE
,
FALSE
))
TRG_ACTION_BEFORE
,
FALSE
))
...
@@ -666,6 +670,11 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
...
@@ -666,6 +670,11 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
}
}
DBUG_ASSERT
(
transactional_table
||
!
deleted
||
thd
->
transaction
.
stmt
.
modified_non_trans_table
);
DBUG_ASSERT
(
transactional_table
||
!
deleted
||
thd
->
transaction
.
stmt
.
modified_non_trans_table
);
free_underlaid_joins
(
thd
,
select_lex
);
free_underlaid_joins
(
thd
,
select_lex
);
if
(
thd
->
lex
->
analyze_stmt
)
{
error
=
thd
->
lex
->
explain
->
send_explain
(
thd
);
}
else
if
(
error
<
0
||
if
(
error
<
0
||
(
thd
->
lex
->
ignore
&&
!
thd
->
is_error
()
&&
!
thd
->
is_fatal_error
))
(
thd
->
lex
->
ignore
&&
!
thd
->
is_error
()
&&
!
thd
->
is_fatal_error
))
{
{
...
...
sql/sql_explain.cc
View file @
424d5de8
This diff is collapsed.
Click to expand it.
sql/sql_explain.h
View file @
424d5de8
...
@@ -14,6 +14,38 @@
...
@@ -14,6 +14,38 @@
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Data structures for ANALYZE */
class
Table_access_tracker
{
public:
Table_access_tracker
()
:
r_scans
(
0
),
r_rows
(
0
),
/*r_rows_after_table_cond(0),*/
r_rows_after_where
(
0
)
{}
ha_rows
r_scans
;
/* How many scans were ran on this join_tab */
ha_rows
r_rows
;
/* How many rows we've got after that */
// ha_rows r_rows_after_table_cond; /* Rows after applying the table condition */
ha_rows
r_rows_after_where
;
/* Rows after applying attached part of WHERE */
bool
has_scans
()
{
return
(
r_scans
!=
0
);
}
ha_rows
get_avg_rows
()
{
return
r_scans
?
(
ha_rows
)
rint
((
double
)
r_rows
/
r_scans
)
:
0
;
}
double
get_filtered_after_where
()
{
double
r_filtered
;
if
(
r_rows
>
0
)
r_filtered
=
(
double
)
r_rows_after_where
/
r_rows
;
else
r_filtered
=
1.0
;
return
r_filtered
;
}
};
/**************************************************************************************
/**************************************************************************************
...
@@ -60,10 +92,10 @@ class Explain_node : public Sql_alloc
...
@@ -60,10 +92,10 @@ class Explain_node : public Sql_alloc
}
}
virtual
int
print_explain
(
Explain_query
*
query
,
select_result_sink
*
output
,
virtual
int
print_explain
(
Explain_query
*
query
,
select_result_sink
*
output
,
uint8
explain_flags
)
=
0
;
uint8
explain_flags
,
bool
is_analyze
)
=
0
;
int
print_explain_for_children
(
Explain_query
*
query
,
select_result_sink
*
output
,
int
print_explain_for_children
(
Explain_query
*
query
,
select_result_sink
*
output
,
uint8
explain_flags
);
uint8
explain_flags
,
bool
is_analyze
);
virtual
~
Explain_node
(){}
virtual
~
Explain_node
(){}
};
};
...
@@ -110,6 +142,12 @@ class Explain_select : public Explain_node
...
@@ -110,6 +142,12 @@ class Explain_select : public Explain_node
return
false
;
return
false
;
}
}
/*
This is used to save the results of "late" test_if_skip_sort_order() calls
that are made from JOIN::exec
*/
void
replace_table
(
uint
idx
,
Explain_table_access
*
new_tab
);
public:
public:
int
select_id
;
int
select_id
;
const
char
*
select_type
;
const
char
*
select_type
;
...
@@ -134,7 +172,14 @@ class Explain_select : public Explain_node
...
@@ -134,7 +172,14 @@ class Explain_select : public Explain_node
bool
using_filesort
;
bool
using_filesort
;
int
print_explain
(
Explain_query
*
query
,
select_result_sink
*
output
,
int
print_explain
(
Explain_query
*
query
,
select_result_sink
*
output
,
uint8
explain_flags
);
uint8
explain_flags
,
bool
is_analyze
);
Table_access_tracker
*
get_using_temporary_read_tracker
()
{
return
&
using_temporary_read_tracker
;
}
private:
Table_access_tracker
using_temporary_read_tracker
;
};
};
...
@@ -172,10 +217,23 @@ class Explain_union : public Explain_node
...
@@ -172,10 +217,23 @@ class Explain_union : public Explain_node
union_members
.
append
(
select_no
);
union_members
.
append
(
select_no
);
}
}
int
print_explain
(
Explain_query
*
query
,
select_result_sink
*
output
,
int
print_explain
(
Explain_query
*
query
,
select_result_sink
*
output
,
uint8
explain_flags
);
uint8
explain_flags
,
bool
is_analyze
);
const
char
*
fake_select_type
;
const
char
*
fake_select_type
;
bool
using_filesort
;
bool
using_filesort
;
Table_access_tracker
*
get_fake_select_lex_tracker
()
{
return
&
fake_select_lex_tracker
;
}
Table_access_tracker
*
get_tmptable_read_tracker
()
{
return
&
tmptable_read_tracker
;
}
private:
Table_access_tracker
fake_select_lex_tracker
;
/* This one is for reading after ORDER BY */
Table_access_tracker
tmptable_read_tracker
;
};
};
...
@@ -183,6 +241,7 @@ class Explain_update;
...
@@ -183,6 +241,7 @@ class Explain_update;
class
Explain_delete
;
class
Explain_delete
;
class
Explain_insert
;
class
Explain_insert
;
/*
/*
Explain structure for a query (i.e. a statement).
Explain structure for a query (i.e. a statement).
...
@@ -238,13 +297,14 @@ class Explain_query : public Sql_alloc
...
@@ -238,13 +297,14 @@ class Explain_query : public Sql_alloc
Explain_union
*
get_union
(
uint
select_id
);
Explain_union
*
get_union
(
uint
select_id
);
/* Produce a tabular EXPLAIN output */
/* Produce a tabular EXPLAIN output */
int
print_explain
(
select_result_sink
*
output
,
uint8
explain_flags
);
int
print_explain
(
select_result_sink
*
output
,
uint8
explain_flags
,
bool
is_analyze
);
/* Send tabular EXPLAIN to the client */
/* Send tabular EXPLAIN to the client */
int
send_explain
(
THD
*
thd
);
int
send_explain
(
THD
*
thd
);
/* Return tabular EXPLAIN output as a text string */
/* Return tabular EXPLAIN output as a text string */
bool
print_explain_str
(
THD
*
thd
,
String
*
out_str
);
bool
print_explain_str
(
THD
*
thd
,
String
*
out_str
,
bool
is_analyze
);
/* If true, at least part of EXPLAIN can be printed */
/* If true, at least part of EXPLAIN can be printed */
bool
have_query_plan
()
{
return
insert_plan
||
upd_del_plan
||
get_node
(
1
)
!=
NULL
;
}
bool
have_query_plan
()
{
return
insert_plan
||
upd_del_plan
||
get_node
(
1
)
!=
NULL
;
}
...
@@ -252,6 +312,8 @@ class Explain_query : public Sql_alloc
...
@@ -252,6 +312,8 @@ class Explain_query : public Sql_alloc
void
query_plan_ready
();
void
query_plan_ready
();
MEM_ROOT
*
mem_root
;
MEM_ROOT
*
mem_root
;
Explain_update
*
get_upd_del_plan
()
{
return
upd_del_plan
;
}
private:
private:
/* Explain_delete inherits from Explain_update */
/* Explain_delete inherits from Explain_update */
Explain_update
*
upd_del_plan
;
Explain_update
*
upd_del_plan
;
...
@@ -320,13 +382,17 @@ enum explain_extra_tag
...
@@ -320,13 +382,17 @@ enum explain_extra_tag
};
};
typedef
struct
st_explain_bka_type
class
EXPLAIN_BKA_TYPE
{
{
public:
EXPLAIN_BKA_TYPE
()
:
join_alg
(
NULL
)
{}
bool
incremental
;
bool
incremental
;
const
char
*
join_alg
;
const
char
*
join_alg
;
StringBuffer
<
64
>
mrr_type
;
StringBuffer
<
64
>
mrr_type
;
}
EXPLAIN_BKA_TYPE
;
bool
is_using_jbuf
()
{
return
(
join_alg
!=
NULL
);
}
};
/*
/*
...
@@ -386,6 +452,7 @@ class Explain_quick_select : public Sql_alloc
...
@@ -386,6 +452,7 @@ class Explain_quick_select : public Sql_alloc
/*
/*
EXPLAIN data structure for a single JOIN_TAB.
EXPLAIN data structure for a single JOIN_TAB.
*/
*/
class
Explain_table_access
:
public
Sql_alloc
class
Explain_table_access
:
public
Sql_alloc
{
{
public:
public:
...
@@ -459,8 +526,14 @@ class Explain_table_access : public Sql_alloc
...
@@ -459,8 +526,14 @@ class Explain_table_access : public Sql_alloc
StringBuffer
<
32
>
firstmatch_table_name
;
StringBuffer
<
32
>
firstmatch_table_name
;
int
print_explain
(
select_result_sink
*
output
,
uint8
explain_flags
,
int
print_explain
(
select_result_sink
*
output
,
uint8
explain_flags
,
bool
is_analyze
,
uint
select_id
,
const
char
*
select_type
,
uint
select_id
,
const
char
*
select_type
,
bool
using_temporary
,
bool
using_filesort
);
bool
using_temporary
,
bool
using_filesort
);
/* ANALYZE members*/
Table_access_tracker
tracker
;
Table_access_tracker
jbuf_tracker
;
private:
private:
void
append_tag_name
(
String
*
str
,
enum
explain_extra_tag
tag
);
void
append_tag_name
(
String
*
str
,
enum
explain_extra_tag
tag
);
};
};
...
@@ -502,8 +575,17 @@ class Explain_update : public Explain_node
...
@@ -502,8 +575,17 @@ class Explain_update : public Explain_node
bool
using_filesort
;
bool
using_filesort
;
bool
using_io_buffer
;
bool
using_io_buffer
;
/* ANALYZE members and methods */
ha_rows
r_rows
;
ha_rows
r_rows_after_where
;
inline
void
on_record_read
()
{
r_rows
++
;
}
inline
void
on_record_after_where
()
{
r_rows_after_where
++
;
}
Explain_update
()
:
r_rows
(
0
),
r_rows_after_where
(
0
)
{}
virtual
int
print_explain
(
Explain_query
*
query
,
select_result_sink
*
output
,
virtual
int
print_explain
(
Explain_query
*
query
,
select_result_sink
*
output
,
uint8
explain_flags
);
uint8
explain_flags
,
bool
is_analyze
);
};
};
...
@@ -523,7 +605,7 @@ class Explain_insert : public Explain_node
...
@@ -523,7 +605,7 @@ class Explain_insert : public Explain_node
int
get_select_id
()
{
return
1
;
/* always root */
}
int
get_select_id
()
{
return
1
;
/* always root */
}
int
print_explain
(
Explain_query
*
query
,
select_result_sink
*
output
,
int
print_explain
(
Explain_query
*
query
,
select_result_sink
*
output
,
uint8
explain_flags
);
uint8
explain_flags
,
bool
is_analyze
);
};
};
...
@@ -544,7 +626,7 @@ class Explain_delete: public Explain_update
...
@@ -544,7 +626,7 @@ class Explain_delete: public Explain_update
virtual
int
get_select_id
()
{
return
1
;
/* always root */
}
virtual
int
get_select_id
()
{
return
1
;
/* always root */
}
virtual
int
print_explain
(
Explain_query
*
query
,
select_result_sink
*
output
,
virtual
int
print_explain
(
Explain_query
*
query
,
select_result_sink
*
output
,
uint8
explain_flags
);
uint8
explain_flags
,
bool
is_analyze
);
};
};
sql/sql_join_cache.cc
View file @
424d5de8
...
@@ -2277,11 +2277,13 @@ enum_nested_loop_state JOIN_CACHE::join_matching_records(bool skip_last)
...
@@ -2277,11 +2277,13 @@ enum_nested_loop_state JOIN_CACHE::join_matching_records(bool skip_last)
/* Prepare to read matching candidates from the join buffer */
/* Prepare to read matching candidates from the join buffer */
if
(
prepare_look_for_matches
(
skip_last
))
if
(
prepare_look_for_matches
(
skip_last
))
continue
;
continue
;
join_tab
->
jbuf_tracker
->
r_scans
++
;
uchar
*
rec_ptr
;
uchar
*
rec_ptr
;
/* Read each possible candidate from the buffer and look for matches */
/* Read each possible candidate from the buffer and look for matches */
while
((
rec_ptr
=
get_next_candidate_for_match
()))
while
((
rec_ptr
=
get_next_candidate_for_match
()))
{
{
join_tab
->
jbuf_tracker
->
r_rows
++
;
/*
/*
If only the first match is needed, and, it has been already found for
If only the first match is needed, and, it has been already found for
the next record read from the join buffer, then the record is skipped.
the next record read from the join buffer, then the record is skipped.
...
@@ -2452,6 +2454,8 @@ inline bool JOIN_CACHE::check_match(uchar *rec_ptr)
...
@@ -2452,6 +2454,8 @@ inline bool JOIN_CACHE::check_match(uchar *rec_ptr)
if
(
join_tab
->
select
&&
join_tab
->
select
->
skip_record
(
join
->
thd
)
<=
0
)
if
(
join_tab
->
select
&&
join_tab
->
select
->
skip_record
(
join
->
thd
)
<=
0
)
DBUG_RETURN
(
FALSE
);
DBUG_RETURN
(
FALSE
);
join_tab
->
jbuf_tracker
->
r_rows_after_where
++
;
if
(
!
join_tab
->
is_last_inner_table
())
if
(
!
join_tab
->
is_last_inner_table
())
DBUG_RETURN
(
TRUE
);
DBUG_RETURN
(
TRUE
);
...
@@ -2574,7 +2578,7 @@ enum_nested_loop_state JOIN_CACHE::join_null_complements(bool skip_last)
...
@@ -2574,7 +2578,7 @@ enum_nested_loop_state JOIN_CACHE::join_null_complements(bool skip_last)
none
none
*/
*/
void
JOIN_CACHE
::
save_explain_data
(
struct
st_explain_bka_type
*
explain
)
void
JOIN_CACHE
::
save_explain_data
(
EXPLAIN_BKA_TYPE
*
explain
)
{
{
explain
->
incremental
=
MY_TEST
(
prev_cache
);
explain
->
incremental
=
MY_TEST
(
prev_cache
);
...
@@ -2619,14 +2623,14 @@ static void add_mrr_explain_info(String *str, uint mrr_mode, handler *file)
...
@@ -2619,14 +2623,14 @@ static void add_mrr_explain_info(String *str, uint mrr_mode, handler *file)
}
}
}
}
void
JOIN_CACHE_BKA
::
save_explain_data
(
struct
st_explain_bka_type
*
explain
)
void
JOIN_CACHE_BKA
::
save_explain_data
(
EXPLAIN_BKA_TYPE
*
explain
)
{
{
JOIN_CACHE
::
save_explain_data
(
explain
);
JOIN_CACHE
::
save_explain_data
(
explain
);
add_mrr_explain_info
(
&
explain
->
mrr_type
,
mrr_mode
,
join_tab
->
table
->
file
);
add_mrr_explain_info
(
&
explain
->
mrr_type
,
mrr_mode
,
join_tab
->
table
->
file
);
}
}
void
JOIN_CACHE_BKAH
::
save_explain_data
(
struct
st_explain_bka_type
*
explain
)
void
JOIN_CACHE_BKAH
::
save_explain_data
(
EXPLAIN_BKA_TYPE
*
explain
)
{
{
JOIN_CACHE
::
save_explain_data
(
explain
);
JOIN_CACHE
::
save_explain_data
(
explain
);
add_mrr_explain_info
(
&
explain
->
mrr_type
,
mrr_mode
,
join_tab
->
table
->
file
);
add_mrr_explain_info
(
&
explain
->
mrr_type
,
mrr_mode
,
join_tab
->
table
->
file
);
...
@@ -3333,6 +3337,7 @@ int JOIN_TAB_SCAN::open()
...
@@ -3333,6 +3337,7 @@ int JOIN_TAB_SCAN::open()
{
{
save_or_restore_used_tabs
(
join_tab
,
FALSE
);
save_or_restore_used_tabs
(
join_tab
,
FALSE
);
is_first_record
=
TRUE
;
is_first_record
=
TRUE
;
join_tab
->
tracker
->
r_scans
++
;
return
join_init_read_record
(
join_tab
);
return
join_init_read_record
(
join_tab
);
}
}
...
@@ -3371,8 +3376,14 @@ int JOIN_TAB_SCAN::next()
...
@@ -3371,8 +3376,14 @@ int JOIN_TAB_SCAN::next()
is_first_record
=
FALSE
;
is_first_record
=
FALSE
;
else
else
err
=
info
->
read_record
(
info
);
err
=
info
->
read_record
(
info
);
if
(
!
err
&&
table
->
vfield
)
if
(
!
err
)
{
join_tab
->
tracker
->
r_rows
++
;
if
(
table
->
vfield
)
update_virtual_fields
(
thd
,
table
);
update_virtual_fields
(
thd
,
table
);
}
while
(
!
err
&&
select
&&
(
skip_rc
=
select
->
skip_record
(
thd
))
<=
0
)
while
(
!
err
&&
select
&&
(
skip_rc
=
select
->
skip_record
(
thd
))
<=
0
)
{
{
if
(
thd
->
check_killed
()
||
skip_rc
<
0
)
if
(
thd
->
check_killed
()
||
skip_rc
<
0
)
...
@@ -3382,9 +3393,16 @@ int JOIN_TAB_SCAN::next()
...
@@ -3382,9 +3393,16 @@ int JOIN_TAB_SCAN::next()
meet the condition pushed to the table join_tab.
meet the condition pushed to the table join_tab.
*/
*/
err
=
info
->
read_record
(
info
);
err
=
info
->
read_record
(
info
);
if
(
!
err
&&
table
->
vfield
)
if
(
!
err
)
{
join_tab
->
tracker
->
r_rows
++
;
if
(
table
->
vfield
)
update_virtual_fields
(
thd
,
table
);
update_virtual_fields
(
thd
,
table
);
}
}
}
if
(
!
err
)
join_tab
->
tracker
->
r_rows_after_where
++
;
return
err
;
return
err
;
}
}
...
...
sql/sql_join_cache.h
View file @
424d5de8
...
@@ -63,7 +63,7 @@ typedef struct st_cache_field {
...
@@ -63,7 +63,7 @@ typedef struct st_cache_field {
class
JOIN_TAB_SCAN
;
class
JOIN_TAB_SCAN
;
struct
st_explain_bka_type
;
class
EXPLAIN_BKA_TYPE
;
/*
/*
JOIN_CACHE is the base class to support the implementations of
JOIN_CACHE is the base class to support the implementations of
...
@@ -662,7 +662,7 @@ class JOIN_CACHE :public Sql_alloc
...
@@ -662,7 +662,7 @@ class JOIN_CACHE :public Sql_alloc
enum_nested_loop_state
join_records
(
bool
skip_last
);
enum_nested_loop_state
join_records
(
bool
skip_last
);
/* Add a comment on the join algorithm employed by the join cache */
/* Add a comment on the join algorithm employed by the join cache */
virtual
void
save_explain_data
(
struct
st_explain_bka_type
*
explain
);
virtual
void
save_explain_data
(
EXPLAIN_BKA_TYPE
*
explain
);
THD
*
thd
();
THD
*
thd
();
...
@@ -1340,7 +1340,7 @@ class JOIN_CACHE_BKA :public JOIN_CACHE
...
@@ -1340,7 +1340,7 @@ class JOIN_CACHE_BKA :public JOIN_CACHE
/* Check index condition of the joined table for a record from BKA cache */
/* Check index condition of the joined table for a record from BKA cache */
bool
skip_index_tuple
(
range_id_t
range_info
);
bool
skip_index_tuple
(
range_id_t
range_info
);
void
save_explain_data
(
struct
st_explain_bka_type
*
explain
);
void
save_explain_data
(
EXPLAIN_BKA_TYPE
*
explain
);
};
};
...
@@ -1431,5 +1431,5 @@ class JOIN_CACHE_BKAH :public JOIN_CACHE_BNLH
...
@@ -1431,5 +1431,5 @@ class JOIN_CACHE_BKAH :public JOIN_CACHE_BNLH
/* Check index condition of the joined table for a record from BKAH cache */
/* Check index condition of the joined table for a record from BKAH cache */
bool
skip_index_tuple
(
range_id_t
range_info
);
bool
skip_index_tuple
(
range_id_t
range_info
);
void
save_explain_data
(
struct
st_explain_bka_type
*
explain
);
void
save_explain_data
(
EXPLAIN_BKA_TYPE
*
explain
);
};
};
sql/sql_lex.cc
View file @
424d5de8
...
@@ -483,6 +483,7 @@ void lex_start(THD *thd)
...
@@ -483,6 +483,7 @@ void lex_start(THD *thd)
if
(
lex
->
select_lex
.
group_list_ptrs
)
if
(
lex
->
select_lex
.
group_list_ptrs
)
lex
->
select_lex
.
group_list_ptrs
->
clear
();
lex
->
select_lex
.
group_list_ptrs
->
clear
();
lex
->
describe
=
0
;
lex
->
describe
=
0
;
lex
->
analyze_stmt
=
0
;
lex
->
subqueries
=
FALSE
;
lex
->
subqueries
=
FALSE
;
lex
->
context_analysis_only
=
0
;
lex
->
context_analysis_only
=
0
;
lex
->
derived_tables
=
0
;
lex
->
derived_tables
=
0
;
...
@@ -4181,12 +4182,12 @@ bool st_select_lex::is_merged_child_of(st_select_lex *ancestor)
...
@@ -4181,12 +4182,12 @@ bool st_select_lex::is_merged_child_of(st_select_lex *ancestor)
*/
*/
int
LEX
::
print_explain
(
select_result_sink
*
output
,
uint8
explain_flags
,
int
LEX
::
print_explain
(
select_result_sink
*
output
,
uint8
explain_flags
,
bool
*
printed_anything
)
bool
is_analyze
,
bool
*
printed_anything
)
{
{
int
res
;
int
res
;
if
(
explain
&&
explain
->
have_query_plan
())
if
(
explain
&&
explain
->
have_query_plan
())
{
{
res
=
explain
->
print_explain
(
output
,
explain_flags
);
res
=
explain
->
print_explain
(
output
,
explain_flags
,
is_analyze
);
*
printed_anything
=
true
;
*
printed_anything
=
true
;
}
}
else
else
...
...
sql/sql_lex.h
View file @
424d5de8
...
@@ -2268,6 +2268,7 @@ class Update_plan
...
@@ -2268,6 +2268,7 @@ class Update_plan
void
save_explain_data
(
Explain_query
*
query
);
void
save_explain_data
(
Explain_query
*
query
);
void
save_explain_data_intern
(
Explain_query
*
query
,
Explain_update
*
eu
);
void
save_explain_data_intern
(
Explain_query
*
query
,
Explain_update
*
eu
);
virtual
~
Update_plan
()
{}
virtual
~
Update_plan
()
{}
Update_plan
(
MEM_ROOT
*
mem_root_arg
)
:
Update_plan
(
MEM_ROOT
*
mem_root_arg
)
:
...
@@ -2459,6 +2460,7 @@ struct LEX: public Query_tables_list
...
@@ -2459,6 +2460,7 @@ struct LEX: public Query_tables_list
*/
*/
uint
table_count
;
uint
table_count
;
uint8
describe
;
uint8
describe
;
bool
analyze_stmt
;
/* TRUE<=> this is "ANALYZE $stmt" */
/*
/*
A flag that indicates what kinds of derived tables are present in the
A flag that indicates what kinds of derived tables are present in the
query (0 if no derived tables, otherwise a combination of flags
query (0 if no derived tables, otherwise a combination of flags
...
@@ -2735,7 +2737,7 @@ struct LEX: public Query_tables_list
...
@@ -2735,7 +2737,7 @@ struct LEX: public Query_tables_list
}
}
int
print_explain
(
select_result_sink
*
output
,
uint8
explain_flags
,
int
print_explain
(
select_result_sink
*
output
,
uint8
explain_flags
,
bool
*
printed_anything
);
bool
is_analyze
,
bool
*
printed_anything
);
};
};
...
...
sql/sql_parse.cc
View file @
424d5de8
...
@@ -5233,7 +5233,8 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
...
@@ -5233,7 +5233,8 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
top-level LIMIT
top-level LIMIT
*/
*/
result
->
reset_offset_limit
();
result
->
reset_offset_limit
();
thd
->
lex
->
explain
->
print_explain
(
result
,
thd
->
lex
->
describe
);
thd
->
lex
->
explain
->
print_explain
(
result
,
thd
->
lex
->
describe
,
thd
->
lex
->
analyze_stmt
);
if
(
lex
->
describe
&
DESCRIBE_EXTENDED
)
if
(
lex
->
describe
&
DESCRIBE_EXTENDED
)
{
{
char
buff
[
1024
];
char
buff
[
1024
];
...
@@ -5256,13 +5257,38 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
...
@@ -5256,13 +5257,38 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
delete
result
;
delete
result
;
}
}
else
else
{
//psergey-todo: ANALYZE should hook in here...
select_result
*
save_result
;
Protocol
*
save_protocol
;
if
(
lex
->
analyze_stmt
)
{
save_result
=
result
;
result
=
new
select_send_analyze
();
save_protocol
=
thd
->
protocol
;
thd
->
protocol
=
new
Protocol_discard
(
thd
);
}
else
{
{
if
(
!
result
&&
!
(
result
=
new
select_send
()))
if
(
!
result
&&
!
(
result
=
new
select_send
()))
return
1
;
/* purecov: inspected */
return
1
;
/* purecov: inspected */
}
query_cache_store_query
(
thd
,
all_tables
);
query_cache_store_query
(
thd
,
all_tables
);
res
=
handle_select
(
thd
,
lex
,
result
,
0
);
res
=
handle_select
(
thd
,
lex
,
result
,
0
);
if
(
result
!=
lex
->
result
)
if
(
result
!=
lex
->
result
)
delete
result
;
delete
result
;
if
(
lex
->
analyze_stmt
)
{
result
=
save_result
;
if
(
!
result
&&
!
(
result
=
new
select_send
()))
return
1
;
thd
->
protocol
=
save_protocol
;
thd
->
lex
->
explain
->
send_explain
(
thd
);
if
(
result
!=
lex
->
result
)
delete
result
;
}
}
}
}
}
/* Count number of empty select queries */
/* Count number of empty select queries */
...
...
sql/sql_select.cc
View file @
424d5de8
This diff is collapsed.
Click to expand it.
sql/sql_select.h
View file @
424d5de8
...
@@ -251,6 +251,8 @@ typedef struct st_join_table {
...
@@ -251,6 +251,8 @@ typedef struct st_join_table {
/* Special content for EXPLAIN 'Extra' column or NULL if none */
/* Special content for EXPLAIN 'Extra' column or NULL if none */
enum
explain_extra_tag
info
;
enum
explain_extra_tag
info
;
Table_access_tracker
*
tracker
;
Table_access_tracker
*
jbuf_tracker
;
/*
/*
Bitmap of TAB_INFO_* bits that encodes special line for EXPLAIN 'Extra'
Bitmap of TAB_INFO_* bits that encodes special line for EXPLAIN 'Extra'
column, or 0 if there is no info.
column, or 0 if there is no info.
...
@@ -536,6 +538,11 @@ typedef struct st_join_table {
...
@@ -536,6 +538,11 @@ typedef struct st_join_table {
}
}
void
remove_redundant_bnl_scan_conds
();
void
remove_redundant_bnl_scan_conds
();
void
save_explain_data
(
Explain_table_access
*
eta
,
table_map
prefix_tables
,
bool
distinct
,
struct
st_join_table
*
first_top_tab
);
void
update_explain_data
(
uint
idx
);
}
JOIN_TAB
;
}
JOIN_TAB
;
...
@@ -1848,14 +1855,14 @@ void push_index_cond(JOIN_TAB *tab, uint keyno);
...
@@ -1848,14 +1855,14 @@ void push_index_cond(JOIN_TAB *tab, uint keyno);
/* EXPLAIN-related utility functions */
/* EXPLAIN-related utility functions */
int
print_explain_message_line
(
select_result_sink
*
result
,
int
print_explain_message_line
(
select_result_sink
*
result
,
uint8
options
,
uint8
options
,
bool
is_analyze
,
uint
select_number
,
uint
select_number
,
const
char
*
select_type
,
const
char
*
select_type
,
ha_rows
*
rows
,
ha_rows
*
rows
,
const
char
*
message
);
const
char
*
message
);
void
explain_append_mrr_info
(
QUICK_RANGE_SELECT
*
quick
,
String
*
res
);
void
explain_append_mrr_info
(
QUICK_RANGE_SELECT
*
quick
,
String
*
res
);
int
print_explain_row
(
select_result_sink
*
result
,
int
print_explain_row
(
select_result_sink
*
result
,
uint8
options
,
uint8
options
,
bool
is_analyze
,
uint
select_number
,
uint
select_number
,
const
char
*
select_type
,
const
char
*
select_type
,
const
char
*
table_name
,
const
char
*
table_name
,
...
@@ -1866,6 +1873,8 @@ int print_explain_row(select_result_sink *result,
...
@@ -1866,6 +1873,8 @@ int print_explain_row(select_result_sink *result,
const
char
*
key_len
,
const
char
*
key_len
,
const
char
*
ref
,
const
char
*
ref
,
ha_rows
*
rows
,
ha_rows
*
rows
,
ha_rows
*
r_rows
,
double
r_filtered
,
const
char
*
extra
);
const
char
*
extra
);
void
make_possible_keys_line
(
TABLE
*
table
,
key_map
possible_keys
,
String
*
line
);
void
make_possible_keys_line
(
TABLE
*
table
,
key_map
possible_keys
,
String
*
line
);
...
...
sql/sql_show.cc
View file @
424d5de8
This diff is collapsed.
Click to expand it.
sql/sql_show.h
View file @
424d5de8
...
@@ -150,6 +150,69 @@ class Show_explain_request : public Apc_target::Apc_call
...
@@ -150,6 +150,69 @@ class Show_explain_request : public Apc_target::Apc_call
void
call_in_target_thread
();
void
call_in_target_thread
();
};
};
/**
Condition pushdown used for INFORMATION_SCHEMA / SHOW queries.
This structure is to implement an optimization when
accessing data dictionary data in the INFORMATION_SCHEMA
or SHOW commands.
When the query contain a TABLE_SCHEMA or TABLE_NAME clause,
narrow the search for data based on the constraints given.
*/
typedef
struct
st_lookup_field_values
{
/**
Value of a TABLE_SCHEMA clause.
Note that this value length may exceed @c NAME_LEN.
@sa wild_db_value
*/
LEX_STRING
db_value
;
/**
Value of a TABLE_NAME clause.
Note that this value length may exceed @c NAME_LEN.
@sa wild_table_value
*/
LEX_STRING
table_value
;
/**
True when @c db_value is a LIKE clause,
false when @c db_value is an '=' clause.
*/
bool
wild_db_value
;
/**
True when @c table_value is a LIKE clause,
false when @c table_value is an '=' clause.
*/
bool
wild_table_value
;
}
LOOKUP_FIELD_VALUES
;
/*
INFORMATION_SCHEMA: Execution plan for get_all_tables() call
*/
class
IS_table_read_plan
:
public
Sql_alloc
{
public:
IS_table_read_plan
()
:
no_rows
(
false
)
{}
bool
no_rows
;
LOOKUP_FIELD_VALUES
lookup_field_vals
;
Item
*
partial_cond
;
bool
has_db_lookup_value
()
{
return
(
lookup_field_vals
.
db_value
.
length
&&
!
lookup_field_vals
.
wild_db_value
);
}
bool
has_table_lookup_value
()
{
return
(
lookup_field_vals
.
table_value
.
length
&&
!
lookup_field_vals
.
wild_table_value
);
}
};
bool
optimize_schema_tables_reads
(
JOIN
*
join
);
/* Handle the ignored database directories list for SHOW/I_S. */
/* Handle the ignored database directories list for SHOW/I_S. */
bool
ignore_db_dirs_init
();
bool
ignore_db_dirs_init
();
void
ignore_db_dirs_free
();
void
ignore_db_dirs_free
();
...
...
sql/sql_update.cc
View file @
424d5de8
...
@@ -277,6 +277,7 @@ int mysql_update(THD *thd,
...
@@ -277,6 +277,7 @@ int mysql_update(THD *thd,
List
<
Item
>
all_fields
;
List
<
Item
>
all_fields
;
killed_state
killed_status
=
NOT_KILLED
;
killed_state
killed_status
=
NOT_KILLED
;
Update_plan
query_plan
(
thd
->
mem_root
);
Update_plan
query_plan
(
thd
->
mem_root
);
Explain_update
*
explain
;
query_plan
.
index
=
MAX_KEY
;
query_plan
.
index
=
MAX_KEY
;
query_plan
.
using_filesort
=
FALSE
;
query_plan
.
using_filesort
=
FALSE
;
DBUG_ENTER
(
"mysql_update"
);
DBUG_ENTER
(
"mysql_update"
);
...
@@ -717,15 +718,16 @@ int mysql_update(THD *thd,
...
@@ -717,15 +718,16 @@ int mysql_update(THD *thd,
if
(
table
->
file
->
ha_table_flags
()
&
HA_PARTIAL_COLUMN_READ
)
if
(
table
->
file
->
ha_table_flags
()
&
HA_PARTIAL_COLUMN_READ
)
table
->
prepare_for_position
();
table
->
prepare_for_position
();
explain
=
thd
->
lex
->
explain
->
get_upd_del_plan
();
/*
/*
We can use compare_record() to optimize away updates if
We can use compare_record() to optimize away updates if
the table handler is returning all columns OR if
the table handler is returning all columns OR if
if all updated columns are read
if all updated columns are read
*/
*/
can_compare_record
=
records_are_comparable
(
table
);
can_compare_record
=
records_are_comparable
(
table
);
while
(
!
(
error
=
info
.
read_record
(
&
info
))
&&
!
thd
->
killed
)
while
(
!
(
error
=
info
.
read_record
(
&
info
))
&&
!
thd
->
killed
)
{
{
explain
->
on_record_read
();
if
(
table
->
vfield
)
if
(
table
->
vfield
)
update_virtual_fields
(
thd
,
table
,
update_virtual_fields
(
thd
,
table
,
table
->
triggers
?
VCOL_UPDATE_ALL
:
table
->
triggers
?
VCOL_UPDATE_ALL
:
...
@@ -736,6 +738,7 @@ int mysql_update(THD *thd,
...
@@ -736,6 +738,7 @@ int mysql_update(THD *thd,
if
(
table
->
file
->
was_semi_consistent_read
())
if
(
table
->
file
->
was_semi_consistent_read
())
continue
;
/* repeat the read of the same row if it still exists */
continue
;
/* repeat the read of the same row if it still exists */
explain
->
on_record_after_where
();
store_record
(
table
,
record
[
1
]);
store_record
(
table
,
record
[
1
]);
if
(
fill_record_n_invoke_before_triggers
(
thd
,
table
,
fields
,
values
,
0
,
if
(
fill_record_n_invoke_before_triggers
(
thd
,
table
,
fields
,
values
,
0
,
TRG_EVENT_UPDATE
))
TRG_EVENT_UPDATE
))
...
@@ -993,7 +996,11 @@ int mysql_update(THD *thd,
...
@@ -993,7 +996,11 @@ int mysql_update(THD *thd,
id
=
thd
->
arg_of_last_insert_id_function
?
id
=
thd
->
arg_of_last_insert_id_function
?
thd
->
first_successful_insert_id_in_prev_stmt
:
0
;
thd
->
first_successful_insert_id_in_prev_stmt
:
0
;
if
(
error
<
0
)
if
(
thd
->
lex
->
analyze_stmt
)
{
error
=
thd
->
lex
->
explain
->
send_explain
(
thd
);
}
else
if
(
error
<
0
)
{
{
char
buff
[
MYSQL_ERRMSG_SIZE
];
char
buff
[
MYSQL_ERRMSG_SIZE
];
my_snprintf
(
buff
,
sizeof
(
buff
),
ER
(
ER_UPDATE_INFO
),
(
ulong
)
found
,
my_snprintf
(
buff
,
sizeof
(
buff
),
ER
(
ER_UPDATE_INFO
),
(
ulong
)
found
,
...
...
sql/sql_yacc.yy
View file @
424d5de8
...
@@ -1804,6 +1804,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
...
@@ -1804,6 +1804,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%type <dyncol_def_list> dyncall_create_list
%type <dyncol_def_list> dyncall_create_list
%type <NONE>
%type <NONE>
analyze_stmt_command
query verb_clause create change select do drop insert replace insert2
query verb_clause create change select do drop insert replace insert2
insert_values update delete truncate rename
insert_values update delete truncate rename
show describe load alter optimize keycache preload flush
show describe load alter optimize keycache preload flush
...
@@ -1990,6 +1991,7 @@ verb_clause:
...
@@ -1990,6 +1991,7 @@ verb_clause:
statement:
statement:
alter
alter
| analyze
| analyze
| analyze_stmt_command
| binlog_base64_event
| binlog_base64_event
| call
| call
| change
| change
...
@@ -12766,6 +12768,13 @@ describe_command:
...
@@ -12766,6 +12768,13 @@ describe_command:
| DESCRIBE
| DESCRIBE
;
;
analyze_stmt_command:
ANALYZE_SYM explainable_command
{
Lex->analyze_stmt= true;
}
;
opt_extended_describe:
opt_extended_describe:
/* empty */ {}
/* empty */ {}
| EXTENDED_SYM { Lex->describe|= DESCRIBE_EXTENDED; }
| EXTENDED_SYM { Lex->describe|= DESCRIBE_EXTENDED; }
...
...
sql/table.h
View file @
424d5de8
...
@@ -1499,6 +1499,7 @@ typedef struct st_schema_table
...
@@ -1499,6 +1499,7 @@ typedef struct st_schema_table
uint
i_s_requested_object
;
/* the object we need to open(TABLE | VIEW) */
uint
i_s_requested_object
;
/* the object we need to open(TABLE | VIEW) */
}
ST_SCHEMA_TABLE
;
}
ST_SCHEMA_TABLE
;
class
IS_table_read_plan
;
/*
/*
Types of derived tables. The ending part is a bitmap of phases that are
Types of derived tables. The ending part is a bitmap of phases that are
...
@@ -2044,12 +2045,23 @@ struct TABLE_LIST
...
@@ -2044,12 +2045,23 @@ struct TABLE_LIST
/* TRUE <=> this table is a const one and was optimized away. */
/* TRUE <=> this table is a const one and was optimized away. */
bool
optimized_away
;
bool
optimized_away
;
/* I_S: Flags to open_table (e.g. OPEN_TABLE_ONLY or OPEN_VIEW_ONLY) */
uint
i_s_requested_object
;
uint
i_s_requested_object
;
bool
has_db_lookup_value
;
bool
has_table_lookup_value
;
/*
I_S: how to read the tables (SKIP_OPEN_TABLE/OPEN_FRM_ONLY/OPEN_FULL_TABLE)
*/
uint
table_open_method
;
uint
table_open_method
;
/*
I_S: where the schema table was filled
(this is a hack. The code should be able to figure out whether reading
from I_S should be done by create_sort_index() or by JOIN::exec.)
*/
enum
enum_schema_table_state
schema_table_state
;
enum
enum_schema_table_state
schema_table_state
;
/* Something like a "query plan" for reading INFORMATION_SCHEMA table */
IS_table_read_plan
*
is_table_read_plan
;
MDL_request
mdl_request
;
MDL_request
mdl_request
;
#ifdef WITH_PARTITION_STORAGE_ENGINE
#ifdef WITH_PARTITION_STORAGE_ENGINE
...
...
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