Created
October 3, 2022 19:23
-
-
Save spetrunia/962e17c400e73811172b4ecd03649de7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc | |
index 91b7121bd8d..0b76a5bef46 100644 | |
--- a/sql/opt_subselect.cc | |
+++ b/sql/opt_subselect.cc | |
@@ -3458,9 +3458,11 @@ bool Firstmatch_picker::check_qep(JOIN *join, | |
@@optimizer_switch allows join buffering. | |
- read_time is the same (i.e. FirstMatch doesn't add any cost | |
- remove fanout added by the last table | |
+ (if it is more than 1) | |
*/ | |
- if (*record_count) | |
- *record_count /= join->positions[idx].records_out; | |
+ double inner_fanout= join->positions[idx].records_out; | |
+ if (*record_count && inner_fanout > 1.0) | |
+ *record_count /= inner_fanout; | |
} | |
else | |
{ | |
@@ -3647,7 +3649,8 @@ bool Duplicate_weedout_picker::check_qep(JOIN *join, | |
/* | |
Add the cost of temptable use. The table will have sj_outer_fanout | |
- records, and we will make | |
+ records, and we will make first_weedout_table_rec_count table fill/flush | |
+ iterations. Each of those will have | |
- sj_outer_fanout table writes | |
- sj_inner_fanout*sj_outer_fanout lookups. | |
@@ -3666,6 +3669,17 @@ bool Duplicate_weedout_picker::check_qep(JOIN *join, | |
*read_time= dups_cost + write_cost + full_lookup_cost; | |
*record_count= first_weedout_table_rec_count * sj_outer_fanout; | |
+ if (sj_inner_fanout < 1.0) | |
+ { | |
+ /* | |
+ In some special cases, sj_inner_fanout can be less than 1.0: | |
+ - The subquery may have constructs like | |
+ ... LEFT JOIN empty_table ON ... | |
+ Handling these is on the todo. | |
+ - The subquery tables may have highly-selective conditions. | |
+ */ | |
+ *record_count *= sj_inner_fanout; | |
+ } | |
*handled_fanout= dups_removed_fanout; | |
*strategy= SJ_OPT_DUPS_WEEDOUT; | |
if (unlikely(join->thd->trace_started())) | |
diff --git a/sql/sql_select.cc b/sql/sql_select.cc | |
index 12012e925eb..1bab49f0b5d 100644 | |
--- a/sql/sql_select.cc | |
+++ b/sql/sql_select.cc | |
@@ -10605,9 +10605,26 @@ best_extension_by_limited_search(JOIN *join, | |
{ | |
/* Adjust records_out and current_record_count after semi join */ | |
double ratio= current_record_count / original_record_count; | |
- /* QQQ This is just to stop an assert later */ | |
- if (ratio < 1) | |
+ if (fabs(original_record_count) < COST_EPS) | |
+ { | |
+ /* | |
+ That is, original_record_count=0.0. This happens when we get | |
+ empty tables that are not constant tables. | |
+ Example: t1 LEFT JOIN empty_table ON ... | |
+ QQQ: handle this case properly and avoid zero cardinality. It | |
+ makes the rest of optimization meaningless. | |
+ */ | |
+ } | |
+ else if (ratio <= 1.0) | |
+ { | |
+ /* Normal situation: semi-join processing reduces the cardinality */ | |
position->records_out*= ratio; | |
+ } | |
+ else | |
+ { | |
+ DBUG_ASSERT(0); /* Semi-join increases cardinality? Looks wrong. */ | |
+ } | |
+ | |
if (unlikely(trace_one_table.trace_started())) | |
{ | |
trace_one_table.add("rows_out", position->records_out); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment