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
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
mariadb
Commits
648b957f
Commit
648b957f
authored
Jun 26, 2014
by
Sergei Petrunia
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'bb-10.1-explain-analyze' into 10.1
parents
0bf9fd89
68bf3c50
Changes
23
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
1473 additions
and
578 deletions
+1473
-578
mysql-test/r/analyze_stmt.result
mysql-test/r/analyze_stmt.result
+199
-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
+148
-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
+10
-1
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
+31
-7
sql/sql_select.cc
sql/sql_select.cc
+514
-406
sql/sql_select.h
sql/sql_select.h
+12
-11
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
+18
-8
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 @
648b957f
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;
#
# Check non-merged derived tables
#
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);
update t0 set b=b/3;
analyze select * from (select count(*),max(a),b from t0 group by b) T;
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 10 4 100.00 100.00
2 DERIVED t0 ALL NULL NULL NULL NULL 10 10 100.00 100.00 Using temporary; Using filesort
drop table t0;
#
# Check ORDER/GROUP BY
#
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);
analyze select count(*),max(a),b from t0 where a<7 group by 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 70.00 Using where; Using temporary; Using filesort
drop table t0;
#
# Check multi-table UPDATE/DELETE.
#
create table t0 (a int, b int);
create table t1 (a int, b int);
insert into t0 values (0,0),(2,2),(4,4), (8,8);
insert into t1 values (0,0),(2,2), (6,6);
analyze select * from t0,t1 where t0.a=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 3 3 100.00 100.00
1 SIMPLE t0 ALL NULL NULL NULL NULL 4 4 100.00 16.67 Using where; Using join buffer (flat, BNL join)
analyze update t0,t1 set t1.b=5555 where t0.a=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 3 3 100.00 100.00
1 SIMPLE t0 ALL NULL NULL NULL NULL 4 4 100.00 16.67 Using where
select * from t1;
a b
0 5555
2 5555
6 6
analyze delete t1 from t1, t0 where t0.a=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 3 3 100.00 100.00
1 SIMPLE t0 ALL NULL NULL NULL NULL 4 4 100.00 16.67 Using where
select * from t1;
a b
6 6
drop table t0, t1;
mysql-test/r/ps.result
View file @
648b957f
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 database if exists mysqltest1;
drop database if exists client_test_db;
create table t1
(
...
...
mysql-test/r/show_explain.result
View file @
648b957f
...
...
@@ -641,7 +641,7 @@ set debug_dbug='+d,show_explain_probe_join_exec_start';
SHOW INDEX FROM t1;
show explain for $thr2;
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:
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
...
...
mysql-test/t/analyze_stmt.test
0 → 100644
View file @
648b957f
#
# 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
;
--
echo
#
--
echo
# Check non-merged derived tables
--
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
);
update
t0
set
b
=
b
/
3
;
analyze
select
*
from
(
select
count
(
*
),
max
(
a
),
b
from
t0
group
by
b
)
T
;
drop
table
t0
;
--
echo
#
--
echo
# Check ORDER/GROUP BY
--
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
);
analyze
select
count
(
*
),
max
(
a
),
b
from
t0
where
a
<
7
group
by
b
;
drop
table
t0
;
--
echo
#
--
echo
# Check multi-table UPDATE/DELETE.
--
echo
#
create
table
t0
(
a
int
,
b
int
);
create
table
t1
(
a
int
,
b
int
);
insert
into
t0
values
(
0
,
0
),(
2
,
2
),(
4
,
4
),
(
8
,
8
);
insert
into
t1
values
(
0
,
0
),(
2
,
2
),
(
6
,
6
);
analyze
select
*
from
t0
,
t1
where
t0
.
a
=
t1
.
a
;
analyze
update
t0
,
t1
set
t1
.
b
=
5555
where
t0
.
a
=
t1
.
a
;
select
*
from
t1
;
analyze
delete
t1
from
t1
,
t0
where
t0
.
a
=
t1
.
a
;
select
*
from
t1
;
drop
table
t0
,
t1
;
mysql-test/t/ps.test
View file @
648b957f
...
...
@@ -7,6 +7,7 @@ call mtr.add_suppression('Unsafe statement written to the binary log using state
--
disable_warnings
drop
table
if
exists
t1
,
t2
,
t3
,
t4
;
drop
database
if
exists
mysqltest1
;
# Avoid wrong warnings if mysql_client_test fails
drop
database
if
exists
client_test_db
;
--
enable_warnings
...
...
sql/protocol.h
View file @
648b957f
...
...
@@ -210,6 +210,42 @@ public:
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
);
bool
net_send_error
(
THD
*
thd
,
uint
sql_errno
,
const
char
*
err
,
const
char
*
sqlstate
);
...
...
sql/sql_class.cc
View file @
648b957f
...
...
@@ -2282,6 +2282,9 @@ int THD::send_explain_fields(select_result *result)
/*
Populate the provided field_list with EXPLAIN output columns.
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
)
...
...
@@ -2317,11 +2320,25 @@ void THD::make_explain_field_list(List<Item> &field_list)
item
->
maybe_null
=
1
;
field_list
.
push_back
(
item
=
new
Item_return_int
(
"rows"
,
10
,
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
));
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
;
field_list
.
push_back
(
new
Item_empty_string
(
"Extra"
,
255
,
cs
));
}
...
...
sql/sql_class.h
View file @
648b957f
...
...
@@ -3961,6 +3961,20 @@ public:
};
/*
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
{
protected:
sql_exchange
*
exchange
;
...
...
sql/sql_delete.cc
View file @
648b957f
...
...
@@ -223,6 +223,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
killed_state
killed_status
=
NOT_KILLED
;
THD
::
enum_binlog_query_type
query_type
=
THD
::
ROW_QUERY_TYPE
;
bool
with_select
=
!
select_lex
->
item_list
.
is_empty
();
Explain_delete
*
explain
;
Delete_plan
query_plan
(
thd
->
mem_root
);
query_plan
.
index
=
MAX_KEY
;
query_plan
.
using_filesort
=
FALSE
;
...
...
@@ -538,9 +539,11 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
goto
cleanup
;
}
explain
=
(
Explain_delete
*
)
thd
->
lex
->
explain
->
get_upd_del_plan
();
while
(
!
(
error
=
info
.
read_record
(
&
info
))
&&
!
thd
->
killed
&&
!
thd
->
is_error
())
{
explain
->
on_record_read
();
if
(
table
->
vfield
)
update_virtual_fields
(
thd
,
table
,
table
->
triggers
?
VCOL_UPDATE_ALL
:
...
...
@@ -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
if
(
!
select
||
select
->
skip_record
(
thd
)
>
0
)
{
explain
->
on_record_after_where
();
if
(
table
->
triggers
&&
table
->
triggers
->
process_triggers
(
thd
,
TRG_EVENT_DELETE
,
TRG_ACTION_BEFORE
,
FALSE
))
...
...
@@ -666,6 +670,11 @@ cleanup:
}
DBUG_ASSERT
(
transactional_table
||
!
deleted
||
thd
->
transaction
.
stmt
.
modified_non_trans_table
);
free_underlaid_joins
(
thd
,
select_lex
);
if
(
thd
->
lex
->
analyze_stmt
)
{
error
=
thd
->
lex
->
explain
->
send_explain
(
thd
);
}
else
if
(
error
<
0
||
(
thd
->
lex
->
ignore
&&
!
thd
->
is_error
()
&&
!
thd
->
is_fatal_error
))
{
...
...
@@ -1283,7 +1292,7 @@ bool multi_delete::send_eof()
if
(
local_error
!=
0
)
error_handled
=
TRUE
;
// to force early leave from ::abort_result_set()
if
(
!
local_error
)
if
(
!
local_error
&&
!
thd
->
lex
->
analyze_stmt
)
{
::
my_ok
(
thd
,
deleted
);
}
...
...
sql/sql_explain.cc
View file @
648b957f
This diff is collapsed.
Click to expand it.
sql/sql_explain.h
View file @
648b957f
...
...
@@ -14,6 +14,38 @@
along with this program; if not, write to the Free Software
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 @@ public:
}
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
,
uint8
explain_flags
);
uint8
explain_flags
,
bool
is_analyze
);
virtual
~
Explain_node
(){}
};
...
...
@@ -109,6 +141,12 @@ public:
join_tabs
[
n_join_tabs
++
]
=
tab
;
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:
int
select_id
;
...
...
@@ -134,7 +172,14 @@ public:
bool
using_filesort
;
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 @@ public:
union_members
.
append
(
select_no
);
}
int
print_explain
(
Explain_query
*
query
,
select_result_sink
*
output
,
uint8
explain_flags
);
uint8
explain_flags
,
bool
is_analyze
);
const
char
*
fake_select_type
;
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;
class
Explain_delete
;
class
Explain_insert
;
/*
Explain structure for a query (i.e. a statement).
...
...
@@ -238,13 +297,14 @@ public:
Explain_union
*
get_union
(
uint
select_id
);
/* 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 */
int
send_explain
(
THD
*
thd
);
/* 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 */
bool
have_query_plan
()
{
return
insert_plan
||
upd_del_plan
||
get_node
(
1
)
!=
NULL
;
}
...
...
@@ -252,6 +312,8 @@ public:
void
query_plan_ready
();
MEM_ROOT
*
mem_root
;
Explain_update
*
get_upd_del_plan
()
{
return
upd_del_plan
;
}
private:
/* Explain_delete inherits from Explain_update */
Explain_update
*
upd_del_plan
;
...
...
@@ -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
;
const
char
*
join_alg
;
StringBuffer
<
64
>
mrr_type
;
}
EXPLAIN_BKA_TYPE
;
bool
is_using_jbuf
()
{
return
(
join_alg
!=
NULL
);
}
};
/*
...
...
@@ -386,6 +452,7 @@ private:
/*
EXPLAIN data structure for a single JOIN_TAB.
*/
class
Explain_table_access
:
public
Sql_alloc
{
public:
...
...
@@ -459,8 +526,14 @@ public:
StringBuffer
<
32
>
firstmatch_table_name
;
int
print_explain
(
select_result_sink
*
output
,
uint8
explain_flags
,
bool
is_analyze
,
uint
select_id
,
const
char
*
select_type
,
bool
using_temporary
,
bool
using_filesort
);
/* ANALYZE members*/
Table_access_tracker
tracker
;
Table_access_tracker
jbuf_tracker
;
private:
void
append_tag_name
(
String
*
str
,
enum
explain_extra_tag
tag
);
};
...
...
@@ -502,8 +575,17 @@ public:
bool
using_filesort
;
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
,
uint8
explain_flags
);
uint8
explain_flags
,
bool
is_analyze
);
};
...
...
@@ -523,7 +605,7 @@ public:
int
get_select_id
()
{
return
1
;
/* always root */
}
int
print_explain
(
Explain_query
*
query
,
select_result_sink
*
output
,
uint8
explain_flags
);
uint8
explain_flags
,
bool
is_analyze
);
};
...
...
@@ -544,7 +626,7 @@ public:
virtual
int
get_select_id
()
{
return
1
;
/* always root */
}
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 @
648b957f
...
...
@@ -2260,7 +2260,7 @@ enum_nested_loop_state JOIN_CACHE::join_matching_records(bool skip_last)
*/
goto
finish
;
}
while
(
!
(
error
=
join_tab_scan
->
next
()))
{
if
(
join
->
thd
->
check_killed
())
...
...
@@ -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 */
if
(
prepare_look_for_matches
(
skip_last
))
continue
;
join_tab
->
jbuf_tracker
->
r_scans
++
;
uchar
*
rec_ptr
;
/* Read each possible candidate from the buffer and look for matches */
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
the next record read from the join buffer, then the record is skipped.
...
...
@@ -2451,6 +2453,8 @@ inline bool JOIN_CACHE::check_match(uchar *rec_ptr)
if
(
join_tab
->
select
&&
join_tab
->
select
->
skip_record
(
join
->
thd
)
<=
0
)
DBUG_RETURN
(
FALSE
);
join_tab
->
jbuf_tracker
->
r_rows_after_where
++
;
if
(
!
join_tab
->
is_last_inner_table
())
DBUG_RETURN
(
TRUE
);
...
...
@@ -2574,7 +2578,7 @@ finish:
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
);
...
...
@@ -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
);
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
);
add_mrr_explain_info
(
&
explain
->
mrr_type
,
mrr_mode
,
join_tab
->
table
->
file
);
...
...
@@ -3333,6 +3337,7 @@ int JOIN_TAB_SCAN::open()
{
save_or_restore_used_tabs
(
join_tab
,
FALSE
);
is_first_record
=
TRUE
;
join_tab
->
tracker
->
r_scans
++
;
return
join_init_read_record
(
join_tab
);
}
...
...
@@ -3371,8 +3376,14 @@ int JOIN_TAB_SCAN::next()
is_first_record
=
FALSE
;
else
err
=
info
->
read_record
(
info
);
if
(
!
err
&&
table
->
vfield
)
update_virtual_fields
(
thd
,
table
);
if
(
!
err
)
{
join_tab
->
tracker
->
r_rows
++
;
if
(
table
->
vfield
)
update_virtual_fields
(
thd
,
table
);
}
while
(
!
err
&&
select
&&
(
skip_rc
=
select
->
skip_record
(
thd
))
<=
0
)
{
if
(
thd
->
check_killed
()
||
skip_rc
<
0
)
...
...
@@ -3382,9 +3393,16 @@ int JOIN_TAB_SCAN::next()
meet the condition pushed to the table join_tab.
*/
err
=
info
->
read_record
(
info
);
if
(
!
err
&&
table
->
vfield
)
update_virtual_fields
(
thd
,
table
);
}
if
(
!
err
)
{
join_tab
->
tracker
->
r_rows
++
;
if
(
table
->
vfield
)
update_virtual_fields
(
thd
,
table
);
}
}
if
(
!
err
)
join_tab
->
tracker
->
r_rows_after_where
++
;
return
err
;
}
...
...
sql/sql_join_cache.h
View file @
648b957f
...
...
@@ -63,7 +63,7 @@ typedef struct st_cache_field {
class
JOIN_TAB_SCAN
;
struct
st_explain_bka_type
;
class
EXPLAIN_BKA_TYPE
;
/*
JOIN_CACHE is the base class to support the implementations of
...
...
@@ -662,7 +662,7 @@ public:
enum_nested_loop_state
join_records
(
bool
skip_last
);
/* 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
();
...
...
@@ -1340,7 +1340,7 @@ public:
/* Check index condition of the joined table for a record from BKA cache */
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 @@ public:
/* Check index condition of the joined table for a record from BKAH cache */
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 @
648b957f
...
...
@@ -483,6 +483,7 @@ void lex_start(THD *thd)
if
(
lex
->
select_lex
.
group_list_ptrs
)
lex
->
select_lex
.
group_list_ptrs
->
clear
();
lex
->
describe
=
0
;
lex
->
analyze_stmt
=
0
;
lex
->
subqueries
=
FALSE
;
lex
->
context_analysis_only
=
0
;
lex
->
derived_tables
=
0
;
...
...
@@ -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
,
bool
*
printed_anything
)
bool
is_analyze
,
bool
*
printed_anything
)
{
int
res
;
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
;
}
else
...
...
sql/sql_lex.h
View file @
648b957f
...
...
@@ -2268,6 +2268,7 @@ public:
void
save_explain_data
(
Explain_query
*
query
);
void
save_explain_data_intern
(
Explain_query
*
query
,
Explain_update
*
eu
);
virtual
~
Update_plan
()
{}
Update_plan
(
MEM_ROOT
*
mem_root_arg
)
:
...
...
@@ -2459,6 +2460,7 @@ struct LEX: public Query_tables_list
*/
uint
table_count
;
uint8
describe
;
bool
analyze_stmt
;
/* TRUE<=> this is "ANALYZE $stmt" */
/*
A flag that indicates what kinds of derived tables are present in the
query (0 if no derived tables, otherwise a combination of flags
...
...
@@ -2735,7 +2737,7 @@ struct LEX: public Query_tables_list
}
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 @
648b957f
...
...
@@ -3581,7 +3581,6 @@ end_with_restore_list:
{
DBUG_ASSERT
(
first_table
==
all_tables
&&
first_table
!=
0
);
TABLE_LIST
*
aux_tables
=
thd
->
lex
->
auxiliary_table_list
.
first
;
bool
explain
=
MY_TEST
(
lex
->
describe
);
multi_delete
*
result
;
if
((
res
=
multi_delete_precheck
(
thd
,
all_tables
)))
...
...
@@ -3627,7 +3626,7 @@ end_with_restore_list:
result
->
abort_result_set
();
/* for both DELETE and EXPLAIN DELETE */
else
{
if
(
explain
)
if
(
lex
->
describe
||
lex
->
analyze_stmt
)
res
=
thd
->
lex
->
explain
->
send_explain
(
thd
);
}
delete
result
;
...
...
@@ -5223,7 +5222,7 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
This will call optimize() for all parts of query. The query plan is
printed out below.
*/
res
=
mysql_explain_union
(
thd
,
&
thd
->
lex
->
unit
,
result
);
res
=
mysql_explain_union
(
thd
,
&
lex
->
unit
,
result
);
/* Print EXPLAIN only if we don't have an error */
if
(
!
res
)
...
...
@@ -5233,7 +5232,7 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
top-level LIMIT
*/
result
->
reset_offset_limit
();
thd
->
lex
->
explain
->
print_explain
(
result
,
thd
->
lex
->
describe
);
lex
->
explain
->
print_explain
(
result
,
lex
->
describe
,
lex
->
analyze_stmt
);
if
(
lex
->
describe
&
DESCRIBE_EXTENDED
)
{
char
buff
[
1024
];
...
...
@@ -5243,7 +5242,7 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
The warnings system requires input in utf8, @see
mysqld_show_warnings().
*/
thd
->
lex
->
unit
.
print
(
&
str
,
QT_TO_SYSTEM_CHARSET
);
lex
->
unit
.
print
(
&
str
,
QT_TO_SYSTEM_CHARSET
);
push_warning
(
thd
,
Sql_condition
::
WARN_LEVEL_NOTE
,
ER_YES
,
str
.
c_ptr_safe
());
}
...
...
@@ -5257,12 +5256,37 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
}
else
{
if
(
!
result
&&
!
(
result
=
new
select_send
()))
return
1
;
/* purecov: inspected */
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
()))
return
1
;
/* purecov: inspected */
}
query_cache_store_query
(
thd
,
all_tables
);
res
=
handle_select
(
thd
,
lex
,
result
,
0
);
if
(
result
!=
lex
->
result
)
delete
result
;
if
(
lex
->
analyze_stmt
)
{
result
=
save_result
;
if
(
!
result
&&
!
(
result
=
new
select_send
()))
return
1
;
delete
thd
->
protocol
;
thd
->
protocol
=
save_protocol
;
thd
->
lex
->
explain
->
send_explain
(
thd
);
if
(
result
!=
lex
->
result
)
delete
result
;
}
}
}
/* Count number of empty select queries */
...
...
sql/sql_select.cc
View file @
648b957f
This diff is collapsed.
Click to expand it.
sql/sql_select.h
View file @
648b957f
...
...
@@ -250,7 +250,9 @@ typedef struct st_join_table {
/* Special content for EXPLAIN 'Extra' column or NULL if none */
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'
column, or 0 if there is no info.
...
...
@@ -536,6 +538,11 @@ typedef struct st_join_table {
}
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
;
...
...
@@ -1342,7 +1349,6 @@ public:
sjm_lookup_tables
=
0
;
filesort_found_rows
=
false
;
exec_saved_explain
=
false
;
/*
The following is needed because JOIN::cleanup(true) may be called for
joins for which JOIN::optimize was aborted with an error before a proper
...
...
@@ -1351,13 +1357,6 @@ public:
table_access_tabs
=
NULL
;
}
/*
TRUE <=> There was a JOIN::exec() call, which saved this JOIN's EXPLAIN.
The idea is that we also save at the end of JOIN::optimize(), but that
might not be the final plan.
*/
bool
exec_saved_explain
;
int
prepare
(
Item
***
rref_pointer_array
,
TABLE_LIST
*
tables
,
uint
wind_num
,
COND
*
conds
,
uint
og_num
,
ORDER
*
order
,
bool
skip_order_by
,
ORDER
*
group
,
Item
*
having
,
ORDER
*
proc_param
,
SELECT_LEX
*
select
,
...
...
@@ -1848,14 +1847,14 @@ void push_index_cond(JOIN_TAB *tab, uint keyno);
/* EXPLAIN-related utility functions */
int
print_explain_message_line
(
select_result_sink
*
result
,
uint8
options
,
uint8
options
,
bool
is_analyze
,
uint
select_number
,
const
char
*
select_type
,
ha_rows
*
rows
,
const
char
*
message
);
void
explain_append_mrr_info
(
QUICK_RANGE_SELECT
*
quick
,
String
*
res
);
int
print_explain_row
(
select_result_sink
*
result
,
uint8
options
,
uint8
options
,
bool
is_analyze
,
uint
select_number
,
const
char
*
select_type
,
const
char
*
table_name
,
...
...
@@ -1866,6 +1865,8 @@ int print_explain_row(select_result_sink *result,
const
char
*
key_len
,
const
char
*
ref
,
ha_rows
*
rows
,
ha_rows
*
r_rows
,
double
r_filtered
,
const
char
*
extra
);
void
make_possible_keys_line
(
TABLE
*
table
,
key_map
possible_keys
,
String
*
line
);
...
...
sql/sql_show.cc
View file @
648b957f
This diff is collapsed.
Click to expand it.
sql/sql_show.h
View file @
648b957f
...
...
@@ -150,6 +150,69 @@ public:
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. */
bool
ignore_db_dirs_init
();
void
ignore_db_dirs_free
();
...
...
sql/sql_update.cc
View file @
648b957f
...
...
@@ -277,6 +277,7 @@ int mysql_update(THD *thd,
List
<
Item
>
all_fields
;
killed_state
killed_status
=
NOT_KILLED
;
Update_plan
query_plan
(
thd
->
mem_root
);
Explain_update
*
explain
;
query_plan
.
index
=
MAX_KEY
;
query_plan
.
using_filesort
=
FALSE
;
DBUG_ENTER
(
"mysql_update"
);
...
...
@@ -717,15 +718,16 @@ int mysql_update(THD *thd,
if
(
table
->
file
->
ha_table_flags
()
&
HA_PARTIAL_COLUMN_READ
)
table
->
prepare_for_position
();
explain
=
thd
->
lex
->
explain
->
get_upd_del_plan
();
/*
We can use compare_record() to optimize away updates if
the table handler is returning all columns OR if
if all updated columns are read
*/
can_compare_record
=
records_are_comparable
(
table
);
while
(
!
(
error
=
info
.
read_record
(
&
info
))
&&
!
thd
->
killed
)
{
explain
->
on_record_read
();
if
(
table
->
vfield
)
update_virtual_fields
(
thd
,
table
,
table
->
triggers
?
VCOL_UPDATE_ALL
:
...
...
@@ -736,6 +738,7 @@ int mysql_update(THD *thd,
if
(
table
->
file
->
was_semi_consistent_read
())
continue
;
/* repeat the read of the same row if it still exists */
explain
->
on_record_after_where
();
store_record
(
table
,
record
[
1
]);
if
(
fill_record_n_invoke_before_triggers
(
thd
,
table
,
fields
,
values
,
0
,
TRG_EVENT_UPDATE
))
...
...
@@ -993,7 +996,11 @@ int mysql_update(THD *thd,
id
=
thd
->
arg_of_last_insert_id_function
?
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
];
my_snprintf
(
buff
,
sizeof
(
buff
),
ER
(
ER_UPDATE_INFO
),
(
ulong
)
found
,
...
...
@@ -1563,7 +1570,7 @@ bool mysql_multi_update(THD *thd,
(
*
result
)
->
abort_result_set
();
else
{
if
(
thd
->
lex
->
describe
)
if
(
thd
->
lex
->
describe
||
thd
->
lex
->
analyze_stmt
)
res
=
thd
->
lex
->
explain
->
send_explain
(
thd
);
}
thd
->
abort_on_warning
=
0
;
...
...
@@ -2502,11 +2509,14 @@ bool multi_update::send_eof()
DBUG_RETURN
(
TRUE
);
}
id
=
thd
->
arg_of_last_insert_id_function
?
if
(
!
thd
->
lex
->
analyze_stmt
)
{
id
=
thd
->
arg_of_last_insert_id_function
?
thd
->
first_successful_insert_id_in_prev_stmt
:
0
;
my_snprintf
(
buff
,
sizeof
(
buff
),
ER
(
ER_UPDATE_INFO
),
(
ulong
)
found
,
(
ulong
)
updated
,
(
ulong
)
thd
->
cuted_fields
);
::
my_ok
(
thd
,
(
thd
->
client_capabilities
&
CLIENT_FOUND_ROWS
)
?
found
:
updated
,
id
,
buff
);
my_snprintf
(
buff
,
sizeof
(
buff
),
ER
(
ER_UPDATE_INFO
),
(
ulong
)
found
,
(
ulong
)
updated
,
(
ulong
)
thd
->
cuted_fields
);
::
my_ok
(
thd
,
(
thd
->
client_capabilities
&
CLIENT_FOUND_ROWS
)
?
found
:
updated
,
id
,
buff
);
}
DBUG_RETURN
(
FALSE
);
}
sql/sql_yacc.yy
View file @
648b957f
...
...
@@ -982,7 +982,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
This makes the code grep-able, and helps maintenance.
*/
%token ABORT_SYM /* INTERNAL (used in lex) */
%token ACCESSIBLE_SYM
%token ACTION /* SQL-2003-N */
...
...
@@ -1804,6 +1804,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%type <dyncol_def_list> dyncall_create_list
%type <NONE>
analyze_stmt_command
query verb_clause create change select do drop insert replace insert2
insert_values update delete truncate rename
show describe load alter optimize keycache preload flush
...
...
@@ -1990,6 +1991,7 @@ verb_clause:
statement:
alter
| analyze
| analyze_stmt_command
| binlog_base64_event
| call
| change
...
...
@@ -12766,6 +12768,13 @@ describe_command:
| DESCRIBE
;
analyze_stmt_command:
ANALYZE_SYM explainable_command
{
Lex->analyze_stmt= true;
}
;
opt_extended_describe:
/* empty */ {}
| EXTENDED_SYM { Lex->describe|= DESCRIBE_EXTENDED; }
...
...
sql/table.h
View file @
648b957f
...
...
@@ -1499,6 +1499,7 @@ typedef struct st_schema_table
uint
i_s_requested_object
;
/* the object we need to open(TABLE | VIEW) */
}
ST_SCHEMA_TABLE
;
class
IS_table_read_plan
;
/*
Types of derived tables. The ending part is a bitmap of phases that are
...
...
@@ -2044,12 +2045,23 @@ struct TABLE_LIST
/* TRUE <=> this table is a const one and was 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
;
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
;
/*
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
;
/* Something like a "query plan" for reading INFORMATION_SCHEMA table */
IS_table_read_plan
*
is_table_read_plan
;
MDL_request
mdl_request
;
#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