MDEV-30806: ANALYZE FORMAT=JSON: better support for BNL and BNL-H joins
In block-nl-join, add: - r_loops - this shows how many incoming record combinations this query plan node had. - r_effective_rows - this shows the average number of matching rows that this table had for each incoming record combination. This is comparable with r_rows in non-blocked access methods. For BNL-joins, it is always equal to $.table.r_rows * $.table.r_filtered For BNL-H joins the value cannot be computed from other values Reviewed by: Monty <monty@mariadb.org>
This commit is contained in:
parent
169def14f6
commit
dc1d6213f9
@ -151,7 +151,9 @@ ANALYZE
|
||||
"buffer_type": "flat",
|
||||
"buffer_size": "1Kb",
|
||||
"join_type": "BNL",
|
||||
"r_filtered": 100
|
||||
"r_loops": 20,
|
||||
"r_filtered": 100,
|
||||
"r_effective_rows": 60
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -192,7 +194,9 @@ ANALYZE
|
||||
"buffer_size": "1Kb",
|
||||
"join_type": "BNL",
|
||||
"attached_condition": "tbl1.c > tbl2.c",
|
||||
"r_filtered": 15.83333333
|
||||
"r_loops": 20,
|
||||
"r_filtered": 15.83333333,
|
||||
"r_effective_rows": 60
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -652,7 +656,9 @@ ANALYZE
|
||||
"buffer_size": "65",
|
||||
"join_type": "BNL",
|
||||
"attached_condition": "<in_optimizer>(t2.b,t2.b in (subquery#2))",
|
||||
"r_filtered": null
|
||||
"r_loops": 2,
|
||||
"r_filtered": null,
|
||||
"r_effective_rows": 0
|
||||
},
|
||||
"subqueries": [
|
||||
{
|
||||
@ -742,7 +748,9 @@ ANALYZE
|
||||
"buffer_type": "flat",
|
||||
"buffer_size": "1",
|
||||
"join_type": "BNL",
|
||||
"r_filtered": null
|
||||
"r_loops": 2,
|
||||
"r_filtered": null,
|
||||
"r_effective_rows": 0
|
||||
},
|
||||
"subqueries": [
|
||||
{
|
||||
@ -774,7 +782,9 @@ ANALYZE
|
||||
"buffer_size": "65",
|
||||
"join_type": "BNL",
|
||||
"attached_condition": "t2.f2 = t3.f3",
|
||||
"r_filtered": null
|
||||
"r_loops": 0,
|
||||
"r_filtered": null,
|
||||
"r_effective_rows": null
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -849,3 +859,123 @@ ANALYZE
|
||||
}
|
||||
}
|
||||
drop table t0,t1,t2;
|
||||
#
|
||||
# MDEV-30806: ANALYZE FORMAT=JSON: better support for BNL and BNL-H joins
|
||||
#
|
||||
create table t10 (
|
||||
a int,
|
||||
b int
|
||||
);
|
||||
insert into t10 select seq, seq/3 from seq_0_to_999;
|
||||
create table t11 (
|
||||
a int,
|
||||
b int
|
||||
);
|
||||
insert into t11 select seq, seq/5 from seq_0_to_999;
|
||||
analyze table t10,t11 persistent for all;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t10 analyze status Engine-independent statistics collected
|
||||
test.t10 analyze status OK
|
||||
test.t11 analyze status Engine-independent statistics collected
|
||||
test.t11 analyze status OK
|
||||
analyze format=json
|
||||
select * from t10, t11
|
||||
where
|
||||
t10.a < 700 and
|
||||
t11.a < 100
|
||||
and t10.b=t11.b;
|
||||
ANALYZE
|
||||
{
|
||||
"query_block": {
|
||||
"select_id": 1,
|
||||
"r_loops": 1,
|
||||
"r_total_time_ms": "REPLACED",
|
||||
"table": {
|
||||
"table_name": "t11",
|
||||
"access_type": "ALL",
|
||||
"r_loops": 1,
|
||||
"rows": 1000,
|
||||
"r_rows": 1000,
|
||||
"r_table_time_ms": "REPLACED",
|
||||
"r_other_time_ms": "REPLACED",
|
||||
"filtered": 10.15625,
|
||||
"r_filtered": 10,
|
||||
"attached_condition": "t11.a < 100"
|
||||
},
|
||||
"block-nl-join": {
|
||||
"table": {
|
||||
"table_name": "t10",
|
||||
"access_type": "ALL",
|
||||
"r_loops": 1,
|
||||
"rows": 1000,
|
||||
"r_rows": 1000,
|
||||
"r_table_time_ms": "REPLACED",
|
||||
"r_other_time_ms": "REPLACED",
|
||||
"filtered": 70.3125,
|
||||
"r_filtered": 70,
|
||||
"attached_condition": "t10.a < 700"
|
||||
},
|
||||
"buffer_type": "flat",
|
||||
"buffer_size": "1Kb",
|
||||
"join_type": "BNL",
|
||||
"attached_condition": "t10.b = t11.b",
|
||||
"r_loops": 100,
|
||||
"r_filtered": 0.424285714,
|
||||
"r_effective_rows": 700
|
||||
}
|
||||
}
|
||||
}
|
||||
set @tmp=@@join_cache_level, join_cache_level=6;
|
||||
analyze format=json
|
||||
select * from t10, t11
|
||||
where
|
||||
t10.a < 700 and
|
||||
t11.a < 100
|
||||
and t10.b=t11.b;
|
||||
ANALYZE
|
||||
{
|
||||
"query_block": {
|
||||
"select_id": 1,
|
||||
"r_loops": 1,
|
||||
"r_total_time_ms": "REPLACED",
|
||||
"table": {
|
||||
"table_name": "t11",
|
||||
"access_type": "ALL",
|
||||
"r_loops": 1,
|
||||
"rows": 1000,
|
||||
"r_rows": 1000,
|
||||
"r_table_time_ms": "REPLACED",
|
||||
"r_other_time_ms": "REPLACED",
|
||||
"filtered": 10.15625,
|
||||
"r_filtered": 10,
|
||||
"attached_condition": "t11.a < 100 and t11.b is not null"
|
||||
},
|
||||
"block-nl-join": {
|
||||
"table": {
|
||||
"table_name": "t10",
|
||||
"access_type": "hash_ALL",
|
||||
"key": "#hash#$hj",
|
||||
"key_length": "5",
|
||||
"used_key_parts": ["b"],
|
||||
"ref": ["test.t11.b"],
|
||||
"r_loops": 1,
|
||||
"rows": 1000,
|
||||
"r_rows": 1000,
|
||||
"r_table_time_ms": "REPLACED",
|
||||
"r_other_time_ms": "REPLACED",
|
||||
"filtered": 70.3125,
|
||||
"r_filtered": 70,
|
||||
"attached_condition": "t10.a < 700"
|
||||
},
|
||||
"buffer_type": "flat",
|
||||
"buffer_size": "3Kb",
|
||||
"join_type": "BNLH",
|
||||
"attached_condition": "t10.b = t11.b",
|
||||
"r_loops": 100,
|
||||
"r_filtered": 100,
|
||||
"r_effective_rows": 2.97
|
||||
}
|
||||
}
|
||||
}
|
||||
set join_cache_level=@tmp;
|
||||
drop table t10, t11;
|
||||
|
@ -226,3 +226,45 @@ create table t2 as select * from t1;
|
||||
--source include/analyze-format.inc
|
||||
analyze format=json select a, (select t2.b from t2 where t2.a<t1.a order by t2.c limit 1) from t1 where t1.a<0;
|
||||
drop table t0,t1,t2;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-30806: ANALYZE FORMAT=JSON: better support for BNL and BNL-H joins
|
||||
--echo #
|
||||
--source include/have_sequence.inc
|
||||
create table t10 (
|
||||
a int,
|
||||
b int
|
||||
);
|
||||
insert into t10 select seq, seq/3 from seq_0_to_999;
|
||||
|
||||
create table t11 (
|
||||
a int,
|
||||
b int
|
||||
);
|
||||
insert into t11 select seq, seq/5 from seq_0_to_999;
|
||||
|
||||
analyze table t10,t11 persistent for all;
|
||||
|
||||
--source include/analyze-format.inc
|
||||
analyze format=json
|
||||
select * from t10, t11
|
||||
where
|
||||
t10.a < 700 and
|
||||
t11.a < 100
|
||||
and t10.b=t11.b;
|
||||
|
||||
set @tmp=@@join_cache_level, join_cache_level=6;
|
||||
|
||||
--source include/analyze-format.inc
|
||||
analyze format=json
|
||||
select * from t10, t11
|
||||
where
|
||||
t10.a < 700 and
|
||||
t11.a < 100
|
||||
and t10.b=t11.b;
|
||||
|
||||
set join_cache_level=@tmp;
|
||||
drop table t10, t11;
|
||||
|
||||
|
||||
|
@ -441,7 +441,9 @@ ANALYZE
|
||||
"buffer_size": "65",
|
||||
"join_type": "BNL",
|
||||
"attached_condition": "t3.a = t0.a",
|
||||
"r_filtered": 10
|
||||
"r_loops": 10,
|
||||
"r_filtered": 10,
|
||||
"r_effective_rows": 10
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -516,7 +518,9 @@ ANALYZE
|
||||
"buffer_size": "119",
|
||||
"join_type": "BNL",
|
||||
"attached_condition": "t5.a = t6.a",
|
||||
"r_filtered": 21.42857143
|
||||
"r_loops": 4,
|
||||
"r_filtered": 21.42857143,
|
||||
"r_effective_rows": 7
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -334,7 +334,9 @@ ANALYZE
|
||||
"buffer_type": "flat",
|
||||
"buffer_size": "119",
|
||||
"join_type": "BNL",
|
||||
"r_filtered": 100
|
||||
"r_loops": 2,
|
||||
"r_filtered": 100,
|
||||
"r_effective_rows": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -370,7 +372,9 @@ ANALYZE
|
||||
"buffer_type": "flat",
|
||||
"buffer_size": "119",
|
||||
"join_type": "BNL",
|
||||
"r_filtered": 100
|
||||
"r_loops": 2,
|
||||
"r_filtered": 100,
|
||||
"r_effective_rows": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -435,7 +439,9 @@ ANALYZE
|
||||
"buffer_type": "flat",
|
||||
"buffer_size": "119",
|
||||
"join_type": "BNL",
|
||||
"r_filtered": 100
|
||||
"r_loops": 2,
|
||||
"r_filtered": 100,
|
||||
"r_effective_rows": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -471,7 +477,9 @@ ANALYZE
|
||||
"buffer_type": "flat",
|
||||
"buffer_size": "119",
|
||||
"join_type": "BNL",
|
||||
"r_filtered": 100
|
||||
"r_loops": 2,
|
||||
"r_filtered": 100,
|
||||
"r_effective_rows": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -453,7 +453,9 @@ ANALYZE
|
||||
"buffer_type": "flat",
|
||||
"buffer_size": "119",
|
||||
"join_type": "BNL",
|
||||
"r_filtered": 100
|
||||
"r_loops": 3,
|
||||
"r_filtered": 100,
|
||||
"r_effective_rows": 3
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -489,7 +491,9 @@ ANALYZE
|
||||
"buffer_type": "flat",
|
||||
"buffer_size": "119",
|
||||
"join_type": "BNL",
|
||||
"r_filtered": 100
|
||||
"r_loops": 2,
|
||||
"r_filtered": 100,
|
||||
"r_effective_rows": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -553,7 +557,9 @@ ANALYZE
|
||||
"buffer_type": "flat",
|
||||
"buffer_size": "119",
|
||||
"join_type": "BNL",
|
||||
"r_filtered": 100
|
||||
"r_loops": 3,
|
||||
"r_filtered": 100,
|
||||
"r_effective_rows": 3
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -589,7 +595,9 @@ ANALYZE
|
||||
"buffer_type": "flat",
|
||||
"buffer_size": "119",
|
||||
"join_type": "BNL",
|
||||
"r_filtered": 100
|
||||
"r_loops": 2,
|
||||
"r_filtered": 100,
|
||||
"r_effective_rows": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1544,7 +1544,9 @@ ANALYZE
|
||||
"buffer_size": "400",
|
||||
"join_type": "BKA",
|
||||
"mrr_type": "Rowid-ordered scan",
|
||||
"r_filtered": 100
|
||||
"r_loops": 10,
|
||||
"r_filtered": 100,
|
||||
"r_effective_rows": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -395,7 +395,9 @@ ANALYZE
|
||||
"buffer_type": "flat",
|
||||
"buffer_size": "256Kb",
|
||||
"join_type": "BNL",
|
||||
"r_filtered": 100
|
||||
"r_loops": 3,
|
||||
"r_filtered": 100,
|
||||
"r_effective_rows": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -478,7 +480,9 @@ ANALYZE
|
||||
"buffer_type": "flat",
|
||||
"buffer_size": "256Kb",
|
||||
"join_type": "BNL",
|
||||
"r_filtered": 100
|
||||
"r_loops": 3,
|
||||
"r_filtered": 100,
|
||||
"r_effective_rows": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -426,7 +426,9 @@ ANALYZE
|
||||
"buffer_type": "flat",
|
||||
"buffer_size": "65",
|
||||
"join_type": "BNL",
|
||||
"r_filtered": 100
|
||||
"r_loops": 5,
|
||||
"r_filtered": 100,
|
||||
"r_effective_rows": 7
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -509,7 +511,9 @@ ANALYZE
|
||||
"buffer_type": "flat",
|
||||
"buffer_size": "65",
|
||||
"join_type": "BNL",
|
||||
"r_filtered": 100
|
||||
"r_loops": 5,
|
||||
"r_filtered": 100,
|
||||
"r_effective_rows": 7
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3685,7 +3685,9 @@ ANALYZE
|
||||
"join_type": "BKA",
|
||||
"mrr_type": "Rowid-ordered scan",
|
||||
"attached_condition": "a.atp = 1",
|
||||
"r_filtered": 100
|
||||
"r_loops": 3,
|
||||
"r_filtered": 100,
|
||||
"r_effective_rows": 1
|
||||
},
|
||||
"block-nl-join": {
|
||||
"table": {
|
||||
@ -3709,7 +3711,9 @@ ANALYZE
|
||||
"join_type": "BKA",
|
||||
"mrr_type": "Rowid-ordered scan",
|
||||
"attached_condition": "fi.fh in (6311439873746261694,-397087483897438286,8518228073041491534,-5420422472375069774)",
|
||||
"r_filtered": 40
|
||||
"r_loops": 3,
|
||||
"r_filtered": 40,
|
||||
"r_effective_rows": 26.66666667
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -158,6 +158,25 @@ public:
|
||||
if (unlikely((tracker)->timed)) \
|
||||
{ (tracker)->stop_tracking(thd); }
|
||||
|
||||
|
||||
/*
|
||||
Just a counter to increment one value. Wrapped in a class to be uniform
|
||||
with other counters used by ANALYZE.
|
||||
*/
|
||||
|
||||
class Counter_tracker
|
||||
{
|
||||
public:
|
||||
Counter_tracker() : r_scans(0) {}
|
||||
ha_rows r_scans;
|
||||
|
||||
inline void on_scan_init() { r_scans++; }
|
||||
|
||||
bool has_scans() const { return (r_scans != 0); }
|
||||
ha_rows get_loops() const { return r_scans; }
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
A class for collecting read statistics.
|
||||
|
||||
@ -168,20 +187,16 @@ public:
|
||||
It can be used to track reading from files, buffers, etc).
|
||||
*/
|
||||
|
||||
class Table_access_tracker
|
||||
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)
|
||||
Table_access_tracker() : r_scans(0), r_rows(0), r_rows_after_where(0)
|
||||
{}
|
||||
|
||||
ha_rows r_scans; /* How many scans were ran on this join_tab */
|
||||
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_where; /* Rows after applying attached part of WHERE */
|
||||
|
||||
bool has_scans() const { return (r_scans != 0); }
|
||||
ha_rows get_loops() const { return r_scans; }
|
||||
double get_avg_rows() const
|
||||
{
|
||||
return r_scans
|
||||
@ -200,6 +215,9 @@ public:
|
||||
inline void on_scan_init() { r_scans++; }
|
||||
inline void on_record_read() { r_rows++; }
|
||||
inline void on_record_after_where() { r_rows_after_where++; }
|
||||
|
||||
bool has_scans() const { return (r_scans != 0); }
|
||||
ha_rows get_loops() const { return r_scans; }
|
||||
};
|
||||
|
||||
|
||||
|
@ -1891,12 +1891,29 @@ void Explain_table_access::print_explain_json(Explain_query *query,
|
||||
|
||||
if (is_analyze)
|
||||
{
|
||||
//writer->add_member("r_loops").add_ll(jbuf_tracker.get_loops());
|
||||
writer->add_member("r_loops").add_ll(jbuf_loops_tracker.get_loops());
|
||||
|
||||
writer->add_member("r_filtered");
|
||||
if (jbuf_tracker.has_scans())
|
||||
writer->add_double(jbuf_tracker.get_filtered_after_where()*100.0);
|
||||
else
|
||||
writer->add_null();
|
||||
/*
|
||||
effective_rows is average number of matches we got for an incoming
|
||||
row. The row is stored in the join buffer and then is read
|
||||
from there, possibly multiple times. We can't count this number
|
||||
directly. Infer it as:
|
||||
total_number_of_row_combinations_considered / r_loops.
|
||||
*/
|
||||
writer->add_member("r_effective_rows");
|
||||
if (jbuf_loops_tracker.has_scans())
|
||||
{
|
||||
double loops= (double)jbuf_loops_tracker.get_loops();
|
||||
double row_combinations= (double)jbuf_tracker.r_rows;
|
||||
writer->add_double(row_combinations / loops);
|
||||
}
|
||||
else
|
||||
writer->add_null();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -842,8 +842,12 @@ public:
|
||||
Exec_time_tracker op_tracker;
|
||||
Gap_time_tracker extra_time_tracker;
|
||||
|
||||
/* When using join buffer: Track the reads from join buffer */
|
||||
Table_access_tracker jbuf_tracker;
|
||||
|
||||
/* When using join buffer: Track the number of incoming record combinations */
|
||||
Counter_tracker jbuf_loops_tracker;
|
||||
|
||||
Explain_rowid_filter *rowid_filter;
|
||||
|
||||
int print_explain(select_result_sink *output, uint8 explain_flags,
|
||||
|
@ -21231,6 +21231,8 @@ sub_select_cache(JOIN *join, JOIN_TAB *join_tab, bool end_of_records)
|
||||
/* The user has aborted the execution of the query */
|
||||
DBUG_RETURN(NESTED_LOOP_KILLED);
|
||||
}
|
||||
join_tab->jbuf_loops_tracker->on_scan_init();
|
||||
|
||||
if (!test_if_use_dynamic_range_scan(join_tab))
|
||||
{
|
||||
if (!cache->put_record())
|
||||
@ -27393,6 +27395,7 @@ bool JOIN_TAB::save_explain_data(Explain_table_access *eta,
|
||||
// psergey-todo: data for filtering!
|
||||
tracker= &eta->tracker;
|
||||
jbuf_tracker= &eta->jbuf_tracker;
|
||||
jbuf_loops_tracker= &eta->jbuf_loops_tracker;
|
||||
|
||||
/* Enable the table access time tracker only for "ANALYZE stmt" */
|
||||
if (thd->lex->analyze_stmt)
|
||||
|
@ -309,6 +309,7 @@ typedef struct st_join_table {
|
||||
Table_access_tracker *tracker;
|
||||
|
||||
Table_access_tracker *jbuf_tracker;
|
||||
Counter_tracker *jbuf_loops_tracker;
|
||||
/*
|
||||
Bitmap of TAB_INFO_* bits that encodes special line for EXPLAIN 'Extra'
|
||||
column, or 0 if there is no info.
|
||||
|
Loading…
x
Reference in New Issue
Block a user