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
4106dfe8
Commit
4106dfe8
authored
Mar 24, 2015
by
Sergei Petrunia
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'bb-10.1-explain-analyze' into 10.1
parents
ec68494b
77e16ce7
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
249 additions
and
39 deletions
+249
-39
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
+51
-12
sql/handler.h
sql/handler.h
+5
-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
+0
-22
sql/sql_explain.cc
sql/sql_explain.cc
+12
-1
sql/sql_explain.h
sql/sql_explain.h
+81
-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 @
4106dfe8
...
...
@@ -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 @
4106dfe8
...
...
@@ -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 @
4106dfe8
...
...
@@ -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 @
4106dfe8
...
...
@@ -43,6 +43,8 @@
#include "debug_sync.h" // DEBUG_SYNC
#include "sql_audit.h"
#include "sql_analyze_stmt.h" // tracker in TABLE_IO_WAIT
#ifdef WITH_PARTITION_STORAGE_ENGINE
#include "ha_partition.h"
#endif
...
...
@@ -54,6 +56,17 @@
#include "wsrep_mysqld.h"
#include "wsrep.h"
#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(); \
}
/*
While we have legacy_db_type, we have this array to
check for dups and to find handlerton from legacy_db_type.
...
...
@@ -2566,12 +2579,38 @@ 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
());
}
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
);
TABLE_IO_WAIT
(
tracker
,
m_psi
,
PSI_TABLE_WRITE_ROW
,
MAX_KEY
,
0
,
{
error
=
write_row
(
buf
);
})
MYSQL_INSERT_ROW_DONE
(
error
);
return
error
;
}
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
);
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
;
}
int
handler
::
ha_rnd_next
(
uchar
*
buf
)
{
int
result
;
...
...
@@ -2580,7 +2619,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 +2644,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 +2663,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 +2687,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 +2707,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 +2724,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 +2740,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 +2756,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 +2772,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
)
...
...
@@ -5857,7 +5896,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 +5929,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 +5957,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 @
4106dfe8
...
...
@@ -1571,6 +1571,7 @@ typedef struct {
#define UNDEF_NODEGROUP 65535
class
Item
;
class
Exec_time_tracker
;
struct
st_table_log_memory_entry
;
class
partition_info
;
...
...
@@ -2594,6 +2595,9 @@ public:
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 +2652,7 @@ public:
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
),
...
...
sql/mysqld.cc
View file @
4106dfe8
...
...
@@ -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 @
4106dfe8
...
...
@@ -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 @
4106dfe8
/*
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 @
4106dfe8
...
...
@@ -5271,28 +5271,6 @@ inline int handler::ha_read_first_row(uchar *buf, uint primary_key)
return
error
;
}
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
);
})
MYSQL_INSERT_ROW_DONE
(
error
);
return
error
;
}
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
);})
MYSQL_UPDATE_ROW_DONE
(
error
);
return
error
;
}
extern
pthread_attr_t
*
get_connection_attrib
(
void
);
/**
...
...
sql/sql_explain.cc
View file @
4106dfe8
...
...
@@ -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 @
4106dfe8
...
...
@@ -14,6 +14,44 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "sql_analyze_stmt.h"
/*
== 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 +59,16 @@ public:
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 +81,6 @@ public:
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 +106,39 @@ public:
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 +156,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 +303,9 @@ public:
/* 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 +714,7 @@ public:
// 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 +741,7 @@ public:
/* 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 +811,7 @@ public:
/* 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 @
4106dfe8
...
...
@@ -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 @
4106dfe8
...
...
@@ -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 @@ public:
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 @@ public:
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