Skip to content

Instantly share code, notes, and snippets.

@spetrunia
Created October 3, 2022 19:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save spetrunia/962e17c400e73811172b4ecd03649de7 to your computer and use it in GitHub Desktop.
Save spetrunia/962e17c400e73811172b4ecd03649de7 to your computer and use it in GitHub Desktop.
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