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
3841e921
Commit
3841e921
authored
Mar 25, 2015
by
Sergei Petrunia
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'bb-10.1-explain-analyze' into 10.1
parents
34fcc28e
f42064a1
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
231 additions
and
21 deletions
+231
-21
mysql-test/r/analyze_format_json.result
mysql-test/r/analyze_format_json.result
+25
-0
mysql-test/t/analyze_format_json.test
mysql-test/t/analyze_format_json.test
+8
-0
sql/CMakeLists.txt
sql/CMakeLists.txt
+1
-0
sql/handler.cc
sql/handler.cc
+17
-12
sql/handler.h
sql/handler.h
+18
-0
sql/mysqld.cc
sql/mysqld.cc
+4
-0
sql/mysqld.h
sql/mysqld.h
+3
-0
sql/sql_analyze_stmt.h
sql/sql_analyze_stmt.h
+50
-0
sql/sql_class.h
sql/sql_class.h
+5
-4
sql/sql_explain.cc
sql/sql_explain.cc
+12
-1
sql/sql_explain.h
sql/sql_explain.h
+79
-4
sql/sql_select.cc
sql/sql_select.cc
+4
-0
sql/sql_select.h
sql/sql_select.h
+5
-0
No files found.
mysql-test/r/analyze_format_json.result
View file @
3841e921
...
...
@@ -7,12 +7,15 @@ EXPLAIN
{
"query_block": {
"select_id": 1,
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"table": {
"table_name": "t0",
"access_type": "ALL",
"r_loops": 1,
"rows": 10,
"r_rows": 10,
"r_total_time_ms": "REPLACED",
"filtered": 100,
"r_filtered": 30,
"attached_condition": "(t0.a < 3)"
...
...
@@ -32,12 +35,15 @@ EXPLAIN
{
"query_block": {
"select_id": 1,
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"table": {
"table_name": "t0",
"access_type": "ALL",
"r_loops": 1,
"rows": 10,
"r_rows": 10,
"r_total_time_ms": "REPLACED",
"filtered": 100,
"r_filtered": 0,
"attached_condition": "((t0.a > 9) and (t0.a is not null))"
...
...
@@ -69,12 +75,15 @@ EXPLAIN
{
"query_block": {
"select_id": 1,
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"table": {
"table_name": "t0",
"access_type": "ALL",
"r_loops": 1,
"rows": 10,
"r_rows": 10,
"r_total_time_ms": "REPLACED",
"filtered": 100,
"r_filtered": 100,
"attached_condition": "(t0.a is not null)"
...
...
@@ -90,6 +99,7 @@ EXPLAIN
"r_loops": 10,
"rows": 1,
"r_rows": 1,
"r_total_time_ms": "REPLACED",
"filtered": 100,
"r_filtered": 40,
"attached_condition": "(t1.b < 4)"
...
...
@@ -107,12 +117,15 @@ EXPLAIN
{
"query_block": {
"select_id": 1,
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"table": {
"table_name": "tbl1",
"access_type": "ALL",
"r_loops": 1,
"rows": 100,
"r_rows": 100,
"r_total_time_ms": "REPLACED",
"filtered": 100,
"r_filtered": 20,
"attached_condition": "(tbl1.b < 20)"
...
...
@@ -124,6 +137,7 @@ EXPLAIN
"r_loops": 1,
"rows": 100,
"r_rows": 100,
"r_total_time_ms": "REPLACED",
"filtered": 100,
"r_filtered": 60,
"attached_condition": "(tbl2.b < 60)"
...
...
@@ -140,12 +154,15 @@ EXPLAIN
{
"query_block": {
"select_id": 1,
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"table": {
"table_name": "tbl1",
"access_type": "ALL",
"r_loops": 1,
"rows": 100,
"r_rows": 100,
"r_total_time_ms": "REPLACED",
"filtered": 100,
"r_filtered": 20,
"attached_condition": "(tbl1.b < 20)"
...
...
@@ -157,6 +174,7 @@ EXPLAIN
"r_loops": 1,
"rows": 100,
"r_rows": 100,
"r_total_time_ms": "REPLACED",
"filtered": 100,
"r_filtered": 60,
"attached_condition": "(tbl2.b < 60)"
...
...
@@ -182,12 +200,15 @@ EXPLAIN
{
"query_block": {
"select_id": 1,
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"table": {
"table_name": "t1",
"access_type": "ALL",
"r_loops": 1,
"rows": 10,
"r_rows": 10,
"r_total_time_ms": "REPLACED",
"filtered": 100,
"r_filtered": 100,
"attached_condition": "(t1.a is not null)"
...
...
@@ -203,6 +224,7 @@ EXPLAIN
"r_loops": 10,
"rows": 2,
"r_rows": 0.2,
"r_total_time_ms": "REPLACED",
"filtered": 100,
"r_filtered": 100,
"using_index": true
...
...
@@ -226,12 +248,15 @@ EXPLAIN
{
"query_block": {
"select_id": 1,
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"table": {
"table_name": "t1",
"access_type": "ALL",
"r_loops": 1,
"rows": 10,
"r_rows": 10,
"r_total_time_ms": "REPLACED",
"filtered": 100,
"r_filtered": 50,
"attached_condition": "(test.t1.a < 5)"
...
...
mysql-test/t/analyze_format_json.test
View file @
3841e921
...
...
@@ -9,28 +9,34 @@ create table t0 (a int);
INSERT
INTO
t0
VALUES
(
0
),(
1
),(
2
),(
3
),(
4
),(
5
),(
6
),(
7
),(
8
),(
9
);
--
echo
# r_filtered=30%, because 3 rows match: 0,1,2
--
replace_regex
/
"r_total_time_ms"
:
[
0
-
9
]
*
[
.
]
?
[
0
-
9
]
*/
"r_total_time_ms"
:
"REPLACED"
/
analyze
format
=
json
select
*
from
t0
where
a
<
3
;
create
table
t1
(
a
int
,
b
int
,
c
int
,
key
(
a
));
insert
into
t1
select
A
.
a
*
10
+
B
.
a
,
A
.
a
*
10
+
B
.
a
,
A
.
a
*
10
+
B
.
a
from
t0
A
,
t0
B
;
--
replace_regex
/
"r_total_time_ms"
:
[
0
-
9
]
*
[
.
]
?
[
0
-
9
]
*/
"r_total_time_ms"
:
"REPLACED"
/
analyze
select
*
from
t0
,
t1
where
t1
.
a
=
t0
.
a
and
t0
.
a
>
9
;
--
replace_regex
/
"r_total_time_ms"
:
[
0
-
9
]
*
[
.
]
?
[
0
-
9
]
*/
"r_total_time_ms"
:
"REPLACED"
/
analyze
format
=
json
select
*
from
t0
,
t1
where
t1
.
a
=
t0
.
a
and
t0
.
a
>
9
;
analyze
select
*
from
t0
,
t1
where
t1
.
a
=
t0
.
a
and
t1
.
b
<
4
;
--
replace_regex
/
"r_total_time_ms"
:
[
0
-
9
]
*
[
.
]
?
[
0
-
9
]
*/
"r_total_time_ms"
:
"REPLACED"
/
analyze
format
=
json
select
*
from
t0
,
t1
where
t1
.
a
=
t0
.
a
and
t1
.
b
<
4
;
analyze
select
*
from
t1
tbl1
,
t1
tbl2
where
tbl1
.
b
<
2
and
tbl2
.
b
>
5
;
--
replace_regex
/
"r_total_time_ms"
:
[
0
-
9
]
*
[
.
]
?
[
0
-
9
]
*/
"r_total_time_ms"
:
"REPLACED"
/
analyze
format
=
json
select
*
from
t1
tbl1
,
t1
tbl2
where
tbl1
.
b
<
20
and
tbl2
.
b
<
60
;
--
replace_regex
/
"r_total_time_ms"
:
[
0
-
9
]
*
[
.
]
?
[
0
-
9
]
*/
"r_total_time_ms"
:
"REPLACED"
/
analyze
format
=
json
select
*
from
t1
tbl1
,
t1
tbl2
where
tbl1
.
b
<
20
and
tbl2
.
b
<
60
and
tbl1
.
c
>
tbl2
.
c
;
...
...
@@ -47,6 +53,7 @@ insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create
table
t2
(
a
int
,
key
(
a
));
insert
into
t2
values
(
0
),(
1
);
--
replace_regex
/
"r_total_time_ms"
:
[
0
-
9
]
*
[
.
]
?
[
0
-
9
]
*/
"r_total_time_ms"
:
"REPLACED"
/
analyze
format
=
json
select
*
from
t1
straight_join
t2
force
index
(
a
)
where
t2
.
a
=
t1
.
a
;
drop
table
t1
,
t2
;
...
...
@@ -62,6 +69,7 @@ select database();
connect
(
con1
,
localhost
,
root
,,
*
NO
-
ONE
*
);
connection
con1
;
select
database
();
--
replace_regex
/
"r_total_time_ms"
:
[
0
-
9
]
*
[
.
]
?
[
0
-
9
]
*/
"r_total_time_ms"
:
"REPLACED"
/
analyze
format
=
json
select
*
from
test
.
t1
where
t1
.
a
<
5
;
disconnect
con1
;
connection
default
;
...
...
sql/CMakeLists.txt
View file @
3841e921
...
...
@@ -105,6 +105,7 @@ SET (SQL_SOURCE
# added in MariaDB:
sql_explain.h sql_explain.cc
sql_analyze_stmt.h
sql_lifo_buffer.h sql_join_cache.h sql_join_cache.cc
create_options.cc multi_range_read.cc
opt_index_cond_pushdown.cc opt_subselect.cc
...
...
sql/handler.cc
View file @
3841e921
...
...
@@ -2566,12 +2566,16 @@ int handler::ha_close(void)
status_var_add
(
table
->
in_use
->
status_var
.
rows_tmp_read
,
rows_tmp_read
);
PSI_CALL_close_table
(
m_psi
);
m_psi
=
NULL
;
/* instrumentation handle, invalid after close_table() */
/* Detach from ANALYZE tracker */
tracker
=
NULL
;
DBUG_ASSERT
(
m_lock_type
==
F_UNLCK
);
DBUG_ASSERT
(
inited
==
NONE
);
DBUG_RETURN
(
close
());
}
int
handler
::
ha_rnd_next
(
uchar
*
buf
)
{
int
result
;
...
...
@@ -2580,7 +2584,7 @@ int handler::ha_rnd_next(uchar *buf)
m_lock_type
!=
F_UNLCK
);
DBUG_ASSERT
(
inited
==
RND
);
MYSQL_TABLE_IO_WAIT
(
m_psi
,
PSI_TABLE_FETCH_ROW
,
MAX_KEY
,
0
,
TABLE_IO_WAIT
(
tracker
,
m_psi
,
PSI_TABLE_FETCH_ROW
,
MAX_KEY
,
0
,
{
result
=
rnd_next
(
buf
);
})
if
(
!
result
)
{
...
...
@@ -2605,7 +2609,7 @@ int handler::ha_rnd_pos(uchar *buf, uchar *pos)
/* TODO: Find out how to solve ha_rnd_pos when finding duplicate update. */
/* DBUG_ASSERT(inited == RND); */
MYSQL_TABLE_IO_WAIT
(
m_psi
,
PSI_TABLE_FETCH_ROW
,
MAX_KEY
,
0
,
TABLE_IO_WAIT
(
tracker
,
m_psi
,
PSI_TABLE_FETCH_ROW
,
MAX_KEY
,
0
,
{
result
=
rnd_pos
(
buf
,
pos
);
})
increment_statistics
(
&
SSV
::
ha_read_rnd_count
);
if
(
!
result
)
...
...
@@ -2624,7 +2628,7 @@ int handler::ha_index_read_map(uchar *buf, const uchar *key,
m_lock_type
!=
F_UNLCK
);
DBUG_ASSERT
(
inited
==
INDEX
);
MYSQL_TABLE_IO_WAIT
(
m_psi
,
PSI_TABLE_FETCH_ROW
,
active_index
,
0
,
TABLE_IO_WAIT
(
tracker
,
m_psi
,
PSI_TABLE_FETCH_ROW
,
active_index
,
0
,
{
result
=
index_read_map
(
buf
,
key
,
keypart_map
,
find_flag
);
})
increment_statistics
(
&
SSV
::
ha_read_key_count
);
if
(
!
result
)
...
...
@@ -2648,7 +2652,7 @@ int handler::ha_index_read_idx_map(uchar *buf, uint index, const uchar *key,
DBUG_ASSERT
(
table_share
->
tmp_table
!=
NO_TMP_TABLE
||
m_lock_type
!=
F_UNLCK
);
DBUG_ASSERT
(
end_range
==
NULL
);
MYSQL_TABLE_IO_WAIT
(
m_psi
,
PSI_TABLE_FETCH_ROW
,
index
,
0
,
TABLE_IO_WAIT
(
tracker
,
m_psi
,
PSI_TABLE_FETCH_ROW
,
index
,
0
,
{
result
=
index_read_idx_map
(
buf
,
index
,
key
,
keypart_map
,
find_flag
);
})
increment_statistics
(
&
SSV
::
ha_read_key_count
);
if
(
!
result
)
...
...
@@ -2668,7 +2672,7 @@ int handler::ha_index_next(uchar * buf)
m_lock_type
!=
F_UNLCK
);
DBUG_ASSERT
(
inited
==
INDEX
);
MYSQL_TABLE_IO_WAIT
(
m_psi
,
PSI_TABLE_FETCH_ROW
,
active_index
,
0
,
TABLE_IO_WAIT
(
tracker
,
m_psi
,
PSI_TABLE_FETCH_ROW
,
active_index
,
0
,
{
result
=
index_next
(
buf
);
})
increment_statistics
(
&
SSV
::
ha_read_next_count
);
if
(
!
result
)
...
...
@@ -2685,7 +2689,7 @@ int handler::ha_index_prev(uchar * buf)
m_lock_type
!=
F_UNLCK
);
DBUG_ASSERT
(
inited
==
INDEX
);
MYSQL_TABLE_IO_WAIT
(
m_psi
,
PSI_TABLE_FETCH_ROW
,
active_index
,
0
,
TABLE_IO_WAIT
(
tracker
,
m_psi
,
PSI_TABLE_FETCH_ROW
,
active_index
,
0
,
{
result
=
index_prev
(
buf
);
})
increment_statistics
(
&
SSV
::
ha_read_prev_count
);
if
(
!
result
)
...
...
@@ -2701,7 +2705,7 @@ int handler::ha_index_first(uchar * buf)
m_lock_type
!=
F_UNLCK
);
DBUG_ASSERT
(
inited
==
INDEX
);
MYSQL_TABLE_IO_WAIT
(
m_psi
,
PSI_TABLE_FETCH_ROW
,
active_index
,
0
,
TABLE_IO_WAIT
(
tracker
,
m_psi
,
PSI_TABLE_FETCH_ROW
,
active_index
,
0
,
{
result
=
index_first
(
buf
);
})
increment_statistics
(
&
SSV
::
ha_read_first_count
);
if
(
!
result
)
...
...
@@ -2717,7 +2721,7 @@ int handler::ha_index_last(uchar * buf)
m_lock_type
!=
F_UNLCK
);
DBUG_ASSERT
(
inited
==
INDEX
);
MYSQL_TABLE_IO_WAIT
(
m_psi
,
PSI_TABLE_FETCH_ROW
,
active_index
,
0
,
TABLE_IO_WAIT
(
tracker
,
m_psi
,
PSI_TABLE_FETCH_ROW
,
active_index
,
0
,
{
result
=
index_last
(
buf
);
})
increment_statistics
(
&
SSV
::
ha_read_last_count
);
if
(
!
result
)
...
...
@@ -2733,7 +2737,7 @@ int handler::ha_index_next_same(uchar *buf, const uchar *key, uint keylen)
m_lock_type
!=
F_UNLCK
);
DBUG_ASSERT
(
inited
==
INDEX
);
MYSQL_TABLE_IO_WAIT
(
m_psi
,
PSI_TABLE_FETCH_ROW
,
active_index
,
0
,
TABLE_IO_WAIT
(
tracker
,
m_psi
,
PSI_TABLE_FETCH_ROW
,
active_index
,
0
,
{
result
=
index_next_same
(
buf
,
key
,
keylen
);
})
increment_statistics
(
&
SSV
::
ha_read_next_count
);
if
(
!
result
)
...
...
@@ -5837,6 +5841,7 @@ int handler::ha_reset()
/* reset the bitmaps to point to defaults */
table
->
default_column_bitmaps
();
pushed_cond
=
NULL
;
tracker
=
NULL
;
/* Reset information about pushed engine conditions */
cancel_pushed_idx_cond
();
/* Reset information about pushed index conditions */
...
...
@@ -5857,7 +5862,7 @@ int handler::ha_write_row(uchar *buf)
mark_trx_read_write
();
increment_statistics
(
&
SSV
::
ha_write_count
);
MYSQL_TABLE_IO_WAIT
(
m_psi
,
PSI_TABLE_WRITE_ROW
,
MAX_KEY
,
0
,
TABLE_IO_WAIT
(
tracker
,
m_psi
,
PSI_TABLE_WRITE_ROW
,
MAX_KEY
,
0
,
{
error
=
write_row
(
buf
);
})
MYSQL_INSERT_ROW_DONE
(
error
);
...
...
@@ -5890,7 +5895,7 @@ int handler::ha_update_row(const uchar *old_data, uchar *new_data)
mark_trx_read_write
();
increment_statistics
(
&
SSV
::
ha_update_count
);
MYSQL_TABLE_IO_WAIT
(
m_psi
,
PSI_TABLE_UPDATE_ROW
,
active_index
,
0
,
TABLE_IO_WAIT
(
tracker
,
m_psi
,
PSI_TABLE_UPDATE_ROW
,
active_index
,
0
,
{
error
=
update_row
(
old_data
,
new_data
);})
MYSQL_UPDATE_ROW_DONE
(
error
);
...
...
@@ -5918,7 +5923,7 @@ int handler::ha_delete_row(const uchar *buf)
mark_trx_read_write
();
increment_statistics
(
&
SSV
::
ha_delete_count
);
MYSQL_TABLE_IO_WAIT
(
m_psi
,
PSI_TABLE_DELETE_ROW
,
active_index
,
0
,
TABLE_IO_WAIT
(
tracker
,
m_psi
,
PSI_TABLE_DELETE_ROW
,
active_index
,
0
,
{
error
=
delete_row
(
buf
);})
MYSQL_DELETE_ROW_DONE
(
error
);
if
(
unlikely
(
error
))
...
...
sql/handler.h
View file @
3841e921
...
...
@@ -34,6 +34,8 @@
#include "sql_array.h"
/* Dynamic_array<> */
#include "mdl.h"
#include "sql_analyze_stmt.h" // for Exec_time_tracker
#include <my_compare.h>
#include <ft_global.h>
#include <keycache.h>
...
...
@@ -2594,6 +2596,9 @@ class handler :public Sql_alloc
ulonglong
rows_changed
;
/* One bigger than needed to avoid to test if key == MAX_KEY */
ulonglong
index_rows_read
[
MAX_KEY
+
1
];
/* ANALYZE time tracker, if present */
Exec_time_tracker
*
tracker
;
Item
*
pushed_idx_cond
;
uint
pushed_idx_cond_keyno
;
/* The index which the above condition is for */
...
...
@@ -2648,6 +2653,7 @@ class handler :public Sql_alloc
ft_handler
(
0
),
inited
(
NONE
),
implicit_emptied
(
0
),
pushed_cond
(
0
),
next_insert_id
(
0
),
insert_id_for_cur_row
(
0
),
tracker
(
NULL
),
pushed_idx_cond
(
NULL
),
pushed_idx_cond_keyno
(
MAX_KEY
),
auto_inc_intervals_count
(
0
),
...
...
@@ -4201,6 +4207,18 @@ inline const char *table_case_name(HA_CREATE_INFO *info, const char *name)
return
((
lower_case_table_names
==
2
&&
info
->
alias
)
?
info
->
alias
:
name
);
}
#define TABLE_IO_WAIT(TRACKER, PSI, OP, INDEX, FLAGS, PAYLOAD) \
{ \
if (unlikely(tracker)) \
tracker->start_tracking(); \
\
MYSQL_TABLE_IO_WAIT(PSI, OP, INDEX, FLAGS, PAYLOAD); \
\
if (unlikely(tracker)) \
tracker->stop_tracking(); \
}
void
print_keydup_error
(
TABLE
*
table
,
KEY
*
key
,
const
char
*
msg
,
myf
errflag
);
void
print_keydup_error
(
TABLE
*
table
,
KEY
*
key
,
myf
errflag
);
#endif
sql/mysqld.cc
View file @
3841e921
...
...
@@ -314,6 +314,9 @@ arg_cmp_func Arg_comparator::comparator_matrix[6][2] =
{
&
Arg_comparator
::
compare_decimal
,
&
Arg_comparator
::
compare_e_decimal
},
{
&
Arg_comparator
::
compare_datetime
,
&
Arg_comparator
::
compare_e_datetime
}};
/* Timer info to be used by the SQL layer */
MY_TIMER_INFO
sys_timer_info
;
/* static variables */
#ifdef HAVE_PSI_INTERFACE
...
...
@@ -5461,6 +5464,7 @@ int mysqld_main(int argc, char **argv)
#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
pfs_param
.
m_pfs_instrument
=
const_cast
<
char
*>
(
""
);
#endif
/* WITH_PERFSCHEMA_STORAGE_ENGINE */
my_timer_init
(
&
sys_timer_info
);
int
ho_error
__attribute__
((
unused
))
=
handle_early_options
();
...
...
sql/mysqld.h
View file @
3841e921
...
...
@@ -26,6 +26,7 @@
#include "sql_cmd.h"
#include <my_rnd.h>
#include "my_pthread.h"
#include "my_rdtsc.h"
class
THD
;
struct
handlerton
;
...
...
@@ -60,6 +61,8 @@ typedef Bitmap<((MAX_INDEXES+7)/8*8)> key_map; /* Used for finding keys */
#define OPT_SESSION SHOW_OPT_SESSION
#define OPT_GLOBAL SHOW_OPT_GLOBAL
extern
MY_TIMER_INFO
sys_timer_info
;
/*
Values for --slave-parallel-mode
Must match order in slave_parallel_mode_typelib in sys_vars.cc.
...
...
sql/sql_analyze_stmt.h
0 → 100644
View file @
3841e921
/*
Copyright (c) 2015 MariaDB Corporation Ab
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
A class for tracking time it takes to do a certain action
*/
class
Exec_time_tracker
{
ulonglong
count
;
ulonglong
cycles
;
ulonglong
last_start
;
public:
Exec_time_tracker
()
:
count
(
0
),
cycles
(
0
)
{}
// interface for collecting time
void
start_tracking
()
{
last_start
=
my_timer_cycles
();
}
void
stop_tracking
()
{
ulonglong
last_end
=
my_timer_cycles
();
count
++
;
cycles
+=
last_end
-
last_start
;
}
// interface for getting the time
ulonglong
get_loops
()
{
return
count
;
}
double
get_time_ms
()
{
// convert 'cycles' to milliseconds.
return
1000
*
((
double
)
cycles
)
/
sys_timer_info
.
cycles
.
frequency
;
}
};
sql/sql_class.h
View file @
3841e921
...
...
@@ -5276,8 +5276,8 @@ inline int handler::ha_write_tmp_row(uchar *buf)
int
error
;
MYSQL_INSERT_ROW_START
(
table_share
->
db
.
str
,
table_share
->
table_name
.
str
);
increment_statistics
(
&
SSV
::
ha_tmp_write_count
);
MYSQL_TABLE_IO_WAIT
(
m_psi
,
PSI_TABLE_WRITE_ROW
,
MAX_KEY
,
0
,
{
error
=
write_row
(
buf
);
})
TABLE_IO_WAIT
(
tracker
,
m_psi
,
PSI_TABLE_WRITE_ROW
,
MAX_KEY
,
0
,
{
error
=
write_row
(
buf
);
})
MYSQL_INSERT_ROW_DONE
(
error
);
return
error
;
}
...
...
@@ -5287,12 +5287,13 @@ inline int handler::ha_update_tmp_row(const uchar *old_data, uchar *new_data)
int
error
;
MYSQL_UPDATE_ROW_START
(
table_share
->
db
.
str
,
table_share
->
table_name
.
str
);
increment_statistics
(
&
SSV
::
ha_tmp_update_count
);
MYSQL_TABLE_IO_WAIT
(
m_psi
,
PSI_TABLE_UPDATE_ROW
,
active_index
,
0
,
{
error
=
update_row
(
old_data
,
new_data
);})
TABLE_IO_WAIT
(
tracker
,
m_psi
,
PSI_TABLE_UPDATE_ROW
,
active_index
,
0
,
{
error
=
update_row
(
old_data
,
new_data
);})
MYSQL_UPDATE_ROW_DONE
(
error
);
return
error
;
}
extern
pthread_attr_t
*
get_connection_attrib
(
void
);
/**
...
...
sql/sql_explain.cc
View file @
3841e921
...
...
@@ -732,7 +732,12 @@ void Explain_select::print_explain_json(Explain_query *query,
*/
writer
->
add_member
(
"query_block"
).
start_object
();
writer
->
add_member
(
"select_id"
).
add_ll
(
select_id
);
if
(
is_analyze
&&
time_tracker
.
get_loops
())
{
writer
->
add_member
(
"r_loops"
).
add_ll
(
time_tracker
.
get_loops
());
writer
->
add_member
(
"r_total_time_ms"
).
add_double
(
time_tracker
.
get_time_ms
());
}
if
(
exec_const_cond
)
{
writer
->
add_member
(
"const_condition"
);
...
...
@@ -1289,6 +1294,12 @@ void Explain_table_access::print_explain_json(Explain_query *query,
}
else
writer
->
add_null
();
if
(
op_tracker
.
get_loops
())
{
writer
->
add_member
(
"r_total_time_ms"
).
add_double
(
op_tracker
.
get_time_ms
());
}
}
/* `filtered` */
...
...
sql/sql_explain.h
View file @
3841e921
...
...
@@ -14,6 +14,42 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
== EXPLAIN/ANALYZE architecture ==
=== [SHOW] EXPLAIN data ===
Query optimization produces two data structures:
1. execution data structures themselves (eg. JOINs, JOIN_TAB, etc, etc)
2. Explain data structures.
#2 are self contained set of data structures that has sufficient info to
produce output of SHOW EXPLAIN, EXPLAIN [FORMAT=JSON], or
ANALYZE [FORMAT=JSON], without accessing the execution data structures.
(the only exception is that Explain data structures keep Item* pointers,
and we require that one might call item->print(QT_EXPLAIN) when printing
FORMAT=JSON output)
=== ANALYZE data ===
EXPLAIN data structures have embedded ANALYZE data structures. These are
objects that are used to track how the parts of query plan were executed:
how many times each part of query plan was invoked, how many rows were
read/returned, etc.
Each execution data structure keeps a direct pointer to its ANALYZE data
structure. It is needed so that execution code can quickly increment the
counters.
(note that this increases the set of data that is frequently accessed
during the execution. What is the impact of this?)
Since ANALYZE/EXPLAIN data structures are separated from execution data
structures, it is easy to have them survive until the end of the query,
where we can return ANALYZE [FORMAT=JSON] output to the user, or print
it into the slow query log.
*/
class
String_list
:
public
List
<
char
>
{
...
...
@@ -21,12 +57,16 @@ class String_list: public List<char>
bool
append_str
(
MEM_ROOT
*
mem_root
,
const
char
*
str
);
};
class
Json_writer
;
/*
A class for collecting read statistics.
The idea is that we run several scans. Each scans gets rows, and then filters
some of them out. We count scans, rows, and rows left after filtering.
(note: at the moment, the class is not actually tied to a physical table.
It can be used to track reading from files, buffers, etc).
*/
class
Table_access_tracker
...
...
@@ -39,7 +79,6 @@ class Table_access_tracker
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
);
}
...
...
@@ -65,6 +104,39 @@ class Table_access_tracker
inline
void
on_record_after_where
()
{
r_rows_after_where
++
;
}
};
#if 0
/*
A class to track operations (currently, row reads) on a PSI_table.
*/
class Table_op_tracker
{
PSI_table *psi_table;
/* Table counter values at start. Sum is in picoseconds */
ulonglong start_sum;
ulonglong start_count;
/* Table counter values at end */
ulonglong end_sum;
ulonglong end_count;
public:
void start_tracking(TABLE *table);
// At the moment, print_json will call end_tracking.
void end_tracking();
// this may print nothing if the table was not tracked.
void print_json(Json_writer *writer);
};
#endif
#define ANALYZE_START_TRACKING(tracker) \
if (tracker) \
{ tracker->start_tracking(); }
#define ANALYZE_STOP_TRACKING(tracker) \
if (tracker) \
{ tracker->stop_tracking(); }
/**************************************************************************************
...
...
@@ -82,8 +154,6 @@ const int FAKE_SELECT_LEX_ID= (int)UINT_MAX;
class
Explain_query
;
class
Json_writer
;
/*
A node can be either a SELECT, or a UNION.
*/
...
...
@@ -231,6 +301,9 @@ class Explain_select : public Explain_basic_join
/* Global join attributes. In tabular form, they are printed on the first row */
bool
using_temporary
;
bool
using_filesort
;
/* ANALYZE members */
Exec_time_tracker
time_tracker
;
int
print_explain
(
Explain_query
*
query
,
select_result_sink
*
output
,
uint8
explain_flags
,
bool
is_analyze
);
...
...
@@ -639,7 +712,7 @@ class Explain_table_access : public Sql_alloc
// Valid if ET_USING tag is present
Explain_quick_select
*
quick_info
;
/* Non-NULL value
s
means this tab uses "range checked for each record" */
/* Non-NULL value means this tab uses "range checked for each record" */
Explain_range_checked_fer
*
range_checked_fer
;
bool
full_scan_on_null_key
;
...
...
@@ -666,6 +739,7 @@ class Explain_table_access : public Sql_alloc
/* Tracker for reading the table */
Table_access_tracker
tracker
;
Exec_time_tracker
op_tracker
;
Table_access_tracker
jbuf_tracker
;
int
print_explain
(
select_result_sink
*
output
,
uint8
explain_flags
,
...
...
@@ -735,6 +809,7 @@ class Explain_update : public Explain_node
/* ANALYZE members and methods */
Table_access_tracker
tracker
;
//psergey-todo: io-tracker here.
virtual
int
print_explain
(
Explain_query
*
query
,
select_result_sink
*
output
,
uint8
explain_flags
,
bool
is_analyze
);
...
...
sql/sql_select.cc
View file @
3841e921
...
...
@@ -2390,7 +2390,9 @@ void JOIN::exec()
select_lex
->
select_number
))
dbug_serve_apcs
(
thd
,
1
);
);
ANALYZE_START_TRACKING
(
tracker
);
exec_inner
();
ANALYZE_STOP_TRACKING
(
tracker
);
DBUG_EXECUTE_IF
(
"show_explain_probe_join_exec_end"
,
if
(
dbug_user_var_equals_int
(
thd
,
...
...
@@ -23404,6 +23406,7 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta, table_map prefix_tab
tab
->
tracker
=
&
eta
->
tracker
;
tab
->
jbuf_tracker
=
&
eta
->
jbuf_tracker
;
tab
->
table
->
file
->
tracker
=
&
eta
->
op_tracker
;
/* id and select_type are kept in Explain_select */
/* table */
...
...
@@ -23842,6 +23845,7 @@ int JOIN::save_explain_data_intern(Explain_query *output, bool need_tmp_table,
Explain_select
*
xpl_sel
;
explain_node
=
xpl_sel
=
new
(
output
->
mem_root
)
Explain_select
(
output
->
mem_root
);
table_map
used_tables
=
0
;
tracker
=
&
xpl_sel
->
time_tracker
;
join
->
select_lex
->
set_explain_type
(
true
);
xpl_sel
->
select_id
=
join
->
select_lex
->
select_number
;
...
...
sql/sql_select.h
View file @
3841e921
...
...
@@ -252,6 +252,7 @@ typedef struct st_join_table {
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'
...
...
@@ -1260,6 +1261,8 @@ class JOIN :public Sql_alloc
OPTIMIZATION_DONE
=
2
};
bool
optimized
;
///< flag to avoid double optimization in EXPLAIN
bool
initialized
;
///< flag to avoid double init_execution calls
Exec_time_tracker
*
tracker
;
enum
{
QEP_NOT_PRESENT_YET
,
QEP_AVAILABLE
,
QEP_DELETED
}
have_query_plan
;
...
...
@@ -1354,6 +1357,8 @@ class JOIN :public Sql_alloc
no_rows_in_result_called
=
0
;
positions
=
best_positions
=
0
;
tracker
=
NULL
;
all_fields
=
fields_arg
;
if
(
&
fields_list
!=
&
fields_arg
)
/* Avoid valgrind-warning */
fields_list
=
fields_arg
;
...
...
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