mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
MDEV-7648: Extra data in ANALYZE FORMAT=JSON $stmt
Show total execution time (r_total_time_ms) for various parts of the query: 1. time spent in SELECTs 2. time spent reading rows from storage engines #2 currently gets the data from P_S.
This commit is contained in:
@ -37,6 +37,7 @@
|
|||||||
#define PSI_CALL_get_table_share PSI_TABLE_CALL(get_table_share)
|
#define PSI_CALL_get_table_share PSI_TABLE_CALL(get_table_share)
|
||||||
#define PSI_CALL_release_table_share PSI_TABLE_CALL(release_table_share)
|
#define PSI_CALL_release_table_share PSI_TABLE_CALL(release_table_share)
|
||||||
#define PSI_CALL_drop_table_share PSI_TABLE_CALL(drop_table_share)
|
#define PSI_CALL_drop_table_share PSI_TABLE_CALL(drop_table_share)
|
||||||
|
#define PSI_CALL_get_table_current_stats PSI_TABLE_CALL(get_table_current_stats)
|
||||||
#else
|
#else
|
||||||
#define PSI_CALL_unbind_table(A1) /* no-op */
|
#define PSI_CALL_unbind_table(A1) /* no-op */
|
||||||
#define PSI_CALL_rebind_table(A1,A2,A3) NULL
|
#define PSI_CALL_rebind_table(A1,A2,A3) NULL
|
||||||
@ -45,6 +46,7 @@
|
|||||||
#define PSI_CALL_get_table_share(A1,A2) NULL
|
#define PSI_CALL_get_table_share(A1,A2) NULL
|
||||||
#define PSI_CALL_release_table_share(A1) /* no-op */
|
#define PSI_CALL_release_table_share(A1) /* no-op */
|
||||||
#define PSI_CALL_drop_table_share(A1,A2,A3,A4,A5) /* no-op */
|
#define PSI_CALL_drop_table_share(A1,A2,A3,A4,A5) /* no-op */
|
||||||
|
#define PSI_CALL_get_table_current_stats(A1,A2,A3) /* no-op */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1921,6 +1921,16 @@ typedef struct PSI_digest_locker* (*digest_add_token_v1_t)
|
|||||||
typedef int (*set_thread_connect_attrs_v1_t)(const char *buffer, uint length,
|
typedef int (*set_thread_connect_attrs_v1_t)(const char *buffer, uint length,
|
||||||
const void *from_cs);
|
const void *from_cs);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Get current row read statistics for the specific instance of a table
|
||||||
|
@param table Instance of table we need statistics for
|
||||||
|
@param count OUT Number of operations
|
||||||
|
@param sum OUT Total duration of operations
|
||||||
|
*/
|
||||||
|
typedef void (*get_table_current_stats_v1_t)(PSI_table *table,
|
||||||
|
ulonglong *count,
|
||||||
|
ulonglong *sum);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Performance Schema Interface, version 1.
|
Performance Schema Interface, version 1.
|
||||||
@since PSI_VERSION_1
|
@since PSI_VERSION_1
|
||||||
@ -2122,6 +2132,8 @@ struct PSI_v1
|
|||||||
digest_add_token_v1_t digest_add_token;
|
digest_add_token_v1_t digest_add_token;
|
||||||
/** @sa set_thread_connect_attrs_v1_t. */
|
/** @sa set_thread_connect_attrs_v1_t. */
|
||||||
set_thread_connect_attrs_v1_t set_thread_connect_attrs;
|
set_thread_connect_attrs_v1_t set_thread_connect_attrs;
|
||||||
|
/** @sa get_table_current_stats_v1 */
|
||||||
|
get_table_current_stats_v1_t get_table_current_stats;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @} (end of group Group_PSI_v1) */
|
/** @} (end of group Group_PSI_v1) */
|
||||||
|
@ -512,6 +512,9 @@ typedef struct PSI_digest_locker* (*digest_add_token_v1_t)
|
|||||||
(struct PSI_digest_locker *locker, uint token, struct OPAQUE_LEX_YYSTYPE *yylval);
|
(struct PSI_digest_locker *locker, uint token, struct OPAQUE_LEX_YYSTYPE *yylval);
|
||||||
typedef int (*set_thread_connect_attrs_v1_t)(const char *buffer, uint length,
|
typedef int (*set_thread_connect_attrs_v1_t)(const char *buffer, uint length,
|
||||||
const void *from_cs);
|
const void *from_cs);
|
||||||
|
typedef void (*get_table_current_stats_v1_t)(PSI_table *table,
|
||||||
|
ulonglong *count,
|
||||||
|
ulonglong *sum);
|
||||||
struct PSI_v1
|
struct PSI_v1
|
||||||
{
|
{
|
||||||
register_mutex_v1_t register_mutex;
|
register_mutex_v1_t register_mutex;
|
||||||
@ -612,6 +615,7 @@ struct PSI_v1
|
|||||||
digest_start_v1_t digest_start;
|
digest_start_v1_t digest_start;
|
||||||
digest_add_token_v1_t digest_add_token;
|
digest_add_token_v1_t digest_add_token;
|
||||||
set_thread_connect_attrs_v1_t set_thread_connect_attrs;
|
set_thread_connect_attrs_v1_t set_thread_connect_attrs;
|
||||||
|
get_table_current_stats_v1_t get_table_current_stats;
|
||||||
};
|
};
|
||||||
typedef struct PSI_v1 PSI;
|
typedef struct PSI_v1 PSI;
|
||||||
typedef struct PSI_mutex_info_v1 PSI_mutex_info;
|
typedef struct PSI_mutex_info_v1 PSI_mutex_info;
|
||||||
|
@ -7,12 +7,15 @@ EXPLAIN
|
|||||||
{
|
{
|
||||||
"query_block": {
|
"query_block": {
|
||||||
"select_id": 1,
|
"select_id": 1,
|
||||||
|
"r_loops": 1,
|
||||||
|
"r_total_time_ms": "REPLACED",
|
||||||
"table": {
|
"table": {
|
||||||
"table_name": "t0",
|
"table_name": "t0",
|
||||||
"access_type": "ALL",
|
"access_type": "ALL",
|
||||||
"r_loops": 1,
|
"r_loops": 1,
|
||||||
"rows": 10,
|
"rows": 10,
|
||||||
"r_rows": 10,
|
"r_rows": 10,
|
||||||
|
"r_total_time_ms": "REPLACED",
|
||||||
"filtered": 100,
|
"filtered": 100,
|
||||||
"r_filtered": 30,
|
"r_filtered": 30,
|
||||||
"attached_condition": "(t0.a < 3)"
|
"attached_condition": "(t0.a < 3)"
|
||||||
@ -32,12 +35,15 @@ EXPLAIN
|
|||||||
{
|
{
|
||||||
"query_block": {
|
"query_block": {
|
||||||
"select_id": 1,
|
"select_id": 1,
|
||||||
|
"r_loops": 1,
|
||||||
|
"r_total_time_ms": "REPLACED",
|
||||||
"table": {
|
"table": {
|
||||||
"table_name": "t0",
|
"table_name": "t0",
|
||||||
"access_type": "ALL",
|
"access_type": "ALL",
|
||||||
"r_loops": 1,
|
"r_loops": 1,
|
||||||
"rows": 10,
|
"rows": 10,
|
||||||
"r_rows": 10,
|
"r_rows": 10,
|
||||||
|
"r_total_time_ms": "REPLACED",
|
||||||
"filtered": 100,
|
"filtered": 100,
|
||||||
"r_filtered": 0,
|
"r_filtered": 0,
|
||||||
"attached_condition": "((t0.a > 9) and (t0.a is not null))"
|
"attached_condition": "((t0.a > 9) and (t0.a is not null))"
|
||||||
@ -69,12 +75,15 @@ EXPLAIN
|
|||||||
{
|
{
|
||||||
"query_block": {
|
"query_block": {
|
||||||
"select_id": 1,
|
"select_id": 1,
|
||||||
|
"r_loops": 1,
|
||||||
|
"r_total_time_ms": "REPLACED",
|
||||||
"table": {
|
"table": {
|
||||||
"table_name": "t0",
|
"table_name": "t0",
|
||||||
"access_type": "ALL",
|
"access_type": "ALL",
|
||||||
"r_loops": 1,
|
"r_loops": 1,
|
||||||
"rows": 10,
|
"rows": 10,
|
||||||
"r_rows": 10,
|
"r_rows": 10,
|
||||||
|
"r_total_time_ms": "REPLACED",
|
||||||
"filtered": 100,
|
"filtered": 100,
|
||||||
"r_filtered": 100,
|
"r_filtered": 100,
|
||||||
"attached_condition": "(t0.a is not null)"
|
"attached_condition": "(t0.a is not null)"
|
||||||
@ -90,6 +99,7 @@ EXPLAIN
|
|||||||
"r_loops": 10,
|
"r_loops": 10,
|
||||||
"rows": 1,
|
"rows": 1,
|
||||||
"r_rows": 1,
|
"r_rows": 1,
|
||||||
|
"r_total_time_ms": "REPLACED",
|
||||||
"filtered": 100,
|
"filtered": 100,
|
||||||
"r_filtered": 40,
|
"r_filtered": 40,
|
||||||
"attached_condition": "(t1.b < 4)"
|
"attached_condition": "(t1.b < 4)"
|
||||||
@ -107,12 +117,15 @@ EXPLAIN
|
|||||||
{
|
{
|
||||||
"query_block": {
|
"query_block": {
|
||||||
"select_id": 1,
|
"select_id": 1,
|
||||||
|
"r_loops": 1,
|
||||||
|
"r_total_time_ms": "REPLACED",
|
||||||
"table": {
|
"table": {
|
||||||
"table_name": "tbl1",
|
"table_name": "tbl1",
|
||||||
"access_type": "ALL",
|
"access_type": "ALL",
|
||||||
"r_loops": 1,
|
"r_loops": 1,
|
||||||
"rows": 100,
|
"rows": 100,
|
||||||
"r_rows": 100,
|
"r_rows": 100,
|
||||||
|
"r_total_time_ms": "REPLACED",
|
||||||
"filtered": 100,
|
"filtered": 100,
|
||||||
"r_filtered": 20,
|
"r_filtered": 20,
|
||||||
"attached_condition": "(tbl1.b < 20)"
|
"attached_condition": "(tbl1.b < 20)"
|
||||||
@ -124,6 +137,7 @@ EXPLAIN
|
|||||||
"r_loops": 1,
|
"r_loops": 1,
|
||||||
"rows": 100,
|
"rows": 100,
|
||||||
"r_rows": 100,
|
"r_rows": 100,
|
||||||
|
"r_total_time_ms": "REPLACED",
|
||||||
"filtered": 100,
|
"filtered": 100,
|
||||||
"r_filtered": 60,
|
"r_filtered": 60,
|
||||||
"attached_condition": "(tbl2.b < 60)"
|
"attached_condition": "(tbl2.b < 60)"
|
||||||
@ -140,12 +154,15 @@ EXPLAIN
|
|||||||
{
|
{
|
||||||
"query_block": {
|
"query_block": {
|
||||||
"select_id": 1,
|
"select_id": 1,
|
||||||
|
"r_loops": 1,
|
||||||
|
"r_total_time_ms": "REPLACED",
|
||||||
"table": {
|
"table": {
|
||||||
"table_name": "tbl1",
|
"table_name": "tbl1",
|
||||||
"access_type": "ALL",
|
"access_type": "ALL",
|
||||||
"r_loops": 1,
|
"r_loops": 1,
|
||||||
"rows": 100,
|
"rows": 100,
|
||||||
"r_rows": 100,
|
"r_rows": 100,
|
||||||
|
"r_total_time_ms": "REPLACED",
|
||||||
"filtered": 100,
|
"filtered": 100,
|
||||||
"r_filtered": 20,
|
"r_filtered": 20,
|
||||||
"attached_condition": "(tbl1.b < 20)"
|
"attached_condition": "(tbl1.b < 20)"
|
||||||
@ -157,6 +174,7 @@ EXPLAIN
|
|||||||
"r_loops": 1,
|
"r_loops": 1,
|
||||||
"rows": 100,
|
"rows": 100,
|
||||||
"r_rows": 100,
|
"r_rows": 100,
|
||||||
|
"r_total_time_ms": "REPLACED",
|
||||||
"filtered": 100,
|
"filtered": 100,
|
||||||
"r_filtered": 60,
|
"r_filtered": 60,
|
||||||
"attached_condition": "(tbl2.b < 60)"
|
"attached_condition": "(tbl2.b < 60)"
|
||||||
@ -182,12 +200,15 @@ EXPLAIN
|
|||||||
{
|
{
|
||||||
"query_block": {
|
"query_block": {
|
||||||
"select_id": 1,
|
"select_id": 1,
|
||||||
|
"r_loops": 1,
|
||||||
|
"r_total_time_ms": "REPLACED",
|
||||||
"table": {
|
"table": {
|
||||||
"table_name": "t1",
|
"table_name": "t1",
|
||||||
"access_type": "ALL",
|
"access_type": "ALL",
|
||||||
"r_loops": 1,
|
"r_loops": 1,
|
||||||
"rows": 10,
|
"rows": 10,
|
||||||
"r_rows": 10,
|
"r_rows": 10,
|
||||||
|
"r_total_time_ms": "REPLACED",
|
||||||
"filtered": 100,
|
"filtered": 100,
|
||||||
"r_filtered": 100,
|
"r_filtered": 100,
|
||||||
"attached_condition": "(t1.a is not null)"
|
"attached_condition": "(t1.a is not null)"
|
||||||
@ -203,6 +224,7 @@ EXPLAIN
|
|||||||
"r_loops": 10,
|
"r_loops": 10,
|
||||||
"rows": 2,
|
"rows": 2,
|
||||||
"r_rows": 0.2,
|
"r_rows": 0.2,
|
||||||
|
"r_total_time_ms": "REPLACED",
|
||||||
"filtered": 100,
|
"filtered": 100,
|
||||||
"r_filtered": 100,
|
"r_filtered": 100,
|
||||||
"using_index": true
|
"using_index": true
|
||||||
@ -226,12 +248,15 @@ EXPLAIN
|
|||||||
{
|
{
|
||||||
"query_block": {
|
"query_block": {
|
||||||
"select_id": 1,
|
"select_id": 1,
|
||||||
|
"r_loops": 1,
|
||||||
|
"r_total_time_ms": "REPLACED",
|
||||||
"table": {
|
"table": {
|
||||||
"table_name": "t1",
|
"table_name": "t1",
|
||||||
"access_type": "ALL",
|
"access_type": "ALL",
|
||||||
"r_loops": 1,
|
"r_loops": 1,
|
||||||
"rows": 10,
|
"rows": 10,
|
||||||
"r_rows": 10,
|
"r_rows": 10,
|
||||||
|
"r_total_time_ms": "REPLACED",
|
||||||
"filtered": 100,
|
"filtered": 100,
|
||||||
"r_filtered": 50,
|
"r_filtered": 50,
|
||||||
"attached_condition": "(test.t1.a < 5)"
|
"attached_condition": "(test.t1.a < 5)"
|
||||||
|
@ -9,28 +9,34 @@ create table t0 (a int);
|
|||||||
INSERT INTO t0 VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
|
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
|
--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;
|
analyze format=json select * from t0 where a<3;
|
||||||
|
|
||||||
create table t1 (a int, b int, c int, key(a));
|
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;
|
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
|
analyze
|
||||||
select * from t0, t1 where t1.a=t0.a and t0.a > 9;
|
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
|
analyze format=json
|
||||||
select * from t0, t1 where t1.a=t0.a and t0.a > 9;
|
select * from t0, t1 where t1.a=t0.a and t0.a > 9;
|
||||||
|
|
||||||
analyze
|
analyze
|
||||||
select * from t0, t1 where t1.a=t0.a and t1.b<4;
|
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
|
analyze format=json
|
||||||
select * from t0, t1 where t1.a=t0.a and t1.b<4;
|
select * from t0, t1 where t1.a=t0.a and t1.b<4;
|
||||||
|
|
||||||
analyze
|
analyze
|
||||||
select * from t1 tbl1, t1 tbl2 where tbl1.b<2 and tbl2.b>5;
|
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
|
analyze format=json
|
||||||
select * from t1 tbl1, t1 tbl2 where tbl1.b<20 and tbl2.b<60;
|
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
|
analyze format=json
|
||||||
select * from t1 tbl1, t1 tbl2 where tbl1.b<20 and tbl2.b<60 and tbl1.c > tbl2.c;
|
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));
|
create table t2 (a int, key(a));
|
||||||
insert into t2 values (0),(1);
|
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;
|
analyze format=json select * from t1 straight_join t2 force index(a) where t2.a=t1.a;
|
||||||
|
|
||||||
drop table t1,t2;
|
drop table t1,t2;
|
||||||
@ -62,6 +69,7 @@ select database();
|
|||||||
connect (con1,localhost,root,,*NO-ONE*);
|
connect (con1,localhost,root,,*NO-ONE*);
|
||||||
connection con1;
|
connection con1;
|
||||||
select database();
|
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;
|
analyze format=json select * from test.t1 where t1.a<5;
|
||||||
disconnect con1;
|
disconnect con1;
|
||||||
connection default;
|
connection default;
|
||||||
|
@ -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_decimal, &Arg_comparator::compare_e_decimal},
|
||||||
{&Arg_comparator::compare_datetime, &Arg_comparator::compare_e_datetime}};
|
{&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 */
|
/* static variables */
|
||||||
|
|
||||||
#ifdef HAVE_PSI_INTERFACE
|
#ifdef HAVE_PSI_INTERFACE
|
||||||
@ -5458,6 +5461,7 @@ int mysqld_main(int argc, char **argv)
|
|||||||
#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
|
#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
|
||||||
pfs_param.m_pfs_instrument= const_cast<char*>("");
|
pfs_param.m_pfs_instrument= const_cast<char*>("");
|
||||||
#endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */
|
#endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */
|
||||||
|
my_timer_init(&sys_timer_info);
|
||||||
|
|
||||||
int ho_error __attribute__((unused))= handle_early_options();
|
int ho_error __attribute__((unused))= handle_early_options();
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include "sql_cmd.h"
|
#include "sql_cmd.h"
|
||||||
#include <my_rnd.h>
|
#include <my_rnd.h>
|
||||||
#include "my_pthread.h"
|
#include "my_pthread.h"
|
||||||
|
#include "my_rdtsc.h"
|
||||||
|
|
||||||
class THD;
|
class THD;
|
||||||
struct handlerton;
|
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_SESSION SHOW_OPT_SESSION
|
||||||
#define OPT_GLOBAL SHOW_OPT_GLOBAL
|
#define OPT_GLOBAL SHOW_OPT_GLOBAL
|
||||||
|
|
||||||
|
extern MY_TIMER_INFO sys_timer_info;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Values for --slave-parallel-mode
|
Values for --slave-parallel-mode
|
||||||
Must match order in slave_parallel_mode_typelib in sys_vars.cc.
|
Must match order in slave_parallel_mode_typelib in sys_vars.cc.
|
||||||
|
@ -732,7 +732,12 @@ void Explain_select::print_explain_json(Explain_query *query,
|
|||||||
*/
|
*/
|
||||||
writer->add_member("query_block").start_object();
|
writer->add_member("query_block").start_object();
|
||||||
writer->add_member("select_id").add_ll(select_id);
|
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)
|
if (exec_const_cond)
|
||||||
{
|
{
|
||||||
writer->add_member("const_condition");
|
writer->add_member("const_condition");
|
||||||
@ -1289,6 +1294,9 @@ void Explain_table_access::print_explain_json(Explain_query *query,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
writer->add_null();
|
writer->add_null();
|
||||||
|
|
||||||
|
op_tracker.end_tracking();
|
||||||
|
op_tracker.print_json(writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* `filtered` */
|
/* `filtered` */
|
||||||
@ -1971,3 +1979,40 @@ void create_explain_query_if_not_exists(LEX *lex, MEM_ROOT *mem_root)
|
|||||||
create_explain_query(lex, mem_root);
|
create_explain_query(lex, mem_root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void Table_op_tracker::start_tracking(TABLE *table)
|
||||||
|
{
|
||||||
|
//TODO: will this compile without P_S ?
|
||||||
|
start_count= end_count= 0;
|
||||||
|
if ((psi_table= table->file->m_psi))
|
||||||
|
{
|
||||||
|
PSI_CALL_get_table_current_stats(psi_table, &start_count, &start_sum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Table_op_tracker::end_tracking()
|
||||||
|
{
|
||||||
|
if (psi_table)
|
||||||
|
{
|
||||||
|
PSI_CALL_get_table_current_stats(psi_table, &end_count, &end_sum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Table_op_tracker::print_json(Json_writer *writer)
|
||||||
|
{
|
||||||
|
if (start_count != end_count)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
We have time in picoseconds, we want to print in milli-seconds
|
||||||
|
picosecond is sec* 10^ -12
|
||||||
|
millisecond is sec * 10^-3
|
||||||
|
*/
|
||||||
|
double ms= double(end_sum - start_sum) / 1e9;
|
||||||
|
writer->add_member("r_total_time_ms").add_double(ms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -21,12 +21,16 @@ public:
|
|||||||
bool append_str(MEM_ROOT *mem_root, const char *str);
|
bool append_str(MEM_ROOT *mem_root, const char *str);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Json_writer;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
A class for collecting read statistics.
|
A class for collecting read statistics.
|
||||||
|
|
||||||
The idea is that we run several scans. Each scans gets rows, and then filters
|
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.
|
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
|
class Table_access_tracker
|
||||||
@ -66,6 +70,72 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define ANALYZE_START_TRACKING(tracker) \
|
||||||
|
if (tracker) \
|
||||||
|
{ tracker->start_tracking(); }
|
||||||
|
|
||||||
|
#define ANALYZE_STOP_TRACKING(tracker) \
|
||||||
|
if (tracker) \
|
||||||
|
{ tracker->stop_tracking(); }
|
||||||
|
|
||||||
|
/*
|
||||||
|
A class for tracking execution time
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
//loops, starts, stops
|
||||||
|
ulonglong get_loops() { return count; }
|
||||||
|
double get_time_ms()
|
||||||
|
{
|
||||||
|
// convert 'cycles' to milliseconds.
|
||||||
|
return 1000 * ((double)cycles) / sys_timer_info.cycles.frequency;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**************************************************************************************
|
/**************************************************************************************
|
||||||
|
|
||||||
Data structures for producing EXPLAIN outputs.
|
Data structures for producing EXPLAIN outputs.
|
||||||
@ -82,8 +152,6 @@ const int FAKE_SELECT_LEX_ID= (int)UINT_MAX;
|
|||||||
|
|
||||||
class Explain_query;
|
class Explain_query;
|
||||||
|
|
||||||
class Json_writer;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
A node can be either a SELECT, or a UNION.
|
A node can be either a SELECT, or a UNION.
|
||||||
*/
|
*/
|
||||||
@ -231,6 +299,9 @@ public:
|
|||||||
/* Global join attributes. In tabular form, they are printed on the first row */
|
/* Global join attributes. In tabular form, they are printed on the first row */
|
||||||
bool using_temporary;
|
bool using_temporary;
|
||||||
bool using_filesort;
|
bool using_filesort;
|
||||||
|
|
||||||
|
/* ANALYZE members */
|
||||||
|
Exec_time_tracker time_tracker;
|
||||||
|
|
||||||
int print_explain(Explain_query *query, select_result_sink *output,
|
int print_explain(Explain_query *query, select_result_sink *output,
|
||||||
uint8 explain_flags, bool is_analyze);
|
uint8 explain_flags, bool is_analyze);
|
||||||
@ -666,6 +737,7 @@ public:
|
|||||||
|
|
||||||
/* Tracker for reading the table */
|
/* Tracker for reading the table */
|
||||||
Table_access_tracker tracker;
|
Table_access_tracker tracker;
|
||||||
|
Table_op_tracker op_tracker;
|
||||||
Table_access_tracker jbuf_tracker;
|
Table_access_tracker jbuf_tracker;
|
||||||
|
|
||||||
int print_explain(select_result_sink *output, uint8 explain_flags,
|
int print_explain(select_result_sink *output, uint8 explain_flags,
|
||||||
@ -735,6 +807,7 @@ public:
|
|||||||
|
|
||||||
/* ANALYZE members and methods */
|
/* ANALYZE members and methods */
|
||||||
Table_access_tracker tracker;
|
Table_access_tracker tracker;
|
||||||
|
//psergey-todo: io-tracker here.
|
||||||
|
|
||||||
virtual int print_explain(Explain_query *query, select_result_sink *output,
|
virtual int print_explain(Explain_query *query, select_result_sink *output,
|
||||||
uint8 explain_flags, bool is_analyze);
|
uint8 explain_flags, bool is_analyze);
|
||||||
|
@ -2390,7 +2390,9 @@ void JOIN::exec()
|
|||||||
select_lex->select_number))
|
select_lex->select_number))
|
||||||
dbug_serve_apcs(thd, 1);
|
dbug_serve_apcs(thd, 1);
|
||||||
);
|
);
|
||||||
|
ANALYZE_START_TRACKING(tracker);
|
||||||
exec_inner();
|
exec_inner();
|
||||||
|
ANALYZE_STOP_TRACKING(tracker);
|
||||||
|
|
||||||
DBUG_EXECUTE_IF("show_explain_probe_join_exec_end",
|
DBUG_EXECUTE_IF("show_explain_probe_join_exec_end",
|
||||||
if (dbug_user_var_equals_int(thd,
|
if (dbug_user_var_equals_int(thd,
|
||||||
@ -23417,6 +23419,7 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta, table_map prefix_tab
|
|||||||
tab->tracker= &eta->tracker;
|
tab->tracker= &eta->tracker;
|
||||||
tab->jbuf_tracker= &eta->jbuf_tracker;
|
tab->jbuf_tracker= &eta->jbuf_tracker;
|
||||||
|
|
||||||
|
eta->op_tracker.start_tracking(table);
|
||||||
/* id and select_type are kept in Explain_select */
|
/* id and select_type are kept in Explain_select */
|
||||||
|
|
||||||
/* table */
|
/* table */
|
||||||
@ -23855,6 +23858,7 @@ int JOIN::save_explain_data_intern(Explain_query *output, bool need_tmp_table,
|
|||||||
Explain_select *xpl_sel;
|
Explain_select *xpl_sel;
|
||||||
explain_node= xpl_sel= new (output->mem_root) Explain_select(output->mem_root);
|
explain_node= xpl_sel= new (output->mem_root) Explain_select(output->mem_root);
|
||||||
table_map used_tables=0;
|
table_map used_tables=0;
|
||||||
|
tracker= &xpl_sel->time_tracker;
|
||||||
|
|
||||||
join->select_lex->set_explain_type(true);
|
join->select_lex->set_explain_type(true);
|
||||||
xpl_sel->select_id= join->select_lex->select_number;
|
xpl_sel->select_id= join->select_lex->select_number;
|
||||||
|
@ -252,6 +252,7 @@ typedef struct st_join_table {
|
|||||||
enum explain_extra_tag info;
|
enum explain_extra_tag info;
|
||||||
|
|
||||||
Table_access_tracker *tracker;
|
Table_access_tracker *tracker;
|
||||||
|
|
||||||
Table_access_tracker *jbuf_tracker;
|
Table_access_tracker *jbuf_tracker;
|
||||||
/*
|
/*
|
||||||
Bitmap of TAB_INFO_* bits that encodes special line for EXPLAIN 'Extra'
|
Bitmap of TAB_INFO_* bits that encodes special line for EXPLAIN 'Extra'
|
||||||
@ -1260,6 +1261,8 @@ public:
|
|||||||
OPTIMIZATION_DONE=2};
|
OPTIMIZATION_DONE=2};
|
||||||
bool optimized; ///< flag to avoid double optimization in EXPLAIN
|
bool optimized; ///< flag to avoid double optimization in EXPLAIN
|
||||||
bool initialized; ///< flag to avoid double init_execution calls
|
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;
|
enum { QEP_NOT_PRESENT_YET, QEP_AVAILABLE, QEP_DELETED} have_query_plan;
|
||||||
|
|
||||||
@ -1354,6 +1357,8 @@ public:
|
|||||||
no_rows_in_result_called= 0;
|
no_rows_in_result_called= 0;
|
||||||
positions= best_positions= 0;
|
positions= best_positions= 0;
|
||||||
|
|
||||||
|
tracker= NULL;
|
||||||
|
|
||||||
all_fields= fields_arg;
|
all_fields= fields_arg;
|
||||||
if (&fields_list != &fields_arg) /* Avoid valgrind-warning */
|
if (&fields_list != &fields_arg) /* Avoid valgrind-warning */
|
||||||
fields_list= fields_arg;
|
fields_list= fields_arg;
|
||||||
|
@ -1728,6 +1728,34 @@ static void close_table_v1(PSI_table *table)
|
|||||||
destroy_table(pfs);
|
destroy_table(pfs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Used in ANALYZE-stmt: get current table statistics.
|
||||||
|
*/
|
||||||
|
static void get_table_current_stats_v1(PSI_table *table, ulonglong *count, ulonglong *sum)
|
||||||
|
{
|
||||||
|
PFS_table *pfs= reinterpret_cast<PFS_table*> (table);
|
||||||
|
if (unlikely(pfs == NULL))
|
||||||
|
{
|
||||||
|
*count= 0;
|
||||||
|
*sum= 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
longlong cur_count= 0;
|
||||||
|
longlong cur_sum= 0;
|
||||||
|
|
||||||
|
time_normalizer *normalizer= time_normalizer::get(wait_timer);
|
||||||
|
for (int i=0; i <= MAX_INDEXES; i++)
|
||||||
|
{
|
||||||
|
ulonglong wait= pfs->m_table_stat.m_index_stat[i].m_fetch.m_sum;
|
||||||
|
cur_sum += normalizer->wait_to_pico(wait);
|
||||||
|
cur_count += pfs->m_table_stat.m_index_stat[i].m_fetch.m_count;
|
||||||
|
}
|
||||||
|
*count= cur_count;
|
||||||
|
*sum= cur_sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static PSI_socket*
|
static PSI_socket*
|
||||||
init_socket_v1(PSI_socket_key key, const my_socket *fd,
|
init_socket_v1(PSI_socket_key key, const my_socket *fd,
|
||||||
const struct sockaddr *addr, socklen_t addr_len)
|
const struct sockaddr *addr, socklen_t addr_len)
|
||||||
@ -5245,6 +5273,8 @@ PSI_v1 PFS_v1=
|
|||||||
pfs_digest_start_v1,
|
pfs_digest_start_v1,
|
||||||
pfs_digest_add_token_v1,
|
pfs_digest_add_token_v1,
|
||||||
set_thread_connect_attrs_v1,
|
set_thread_connect_attrs_v1,
|
||||||
|
/* MariaDB's extension: */
|
||||||
|
get_table_current_stats_v1
|
||||||
};
|
};
|
||||||
|
|
||||||
static void* get_interface(int version)
|
static void* get_interface(int version)
|
||||||
|
Reference in New Issue
Block a user