27 #include "sql_planner.h"
28 #include "sql_optimizer.h"
29 #include "opt_range.h"
31 #include "sql_executor.h"
39 static double prev_record_reads(
JOIN *join, uint idx, table_map found_ref);
40 static void trace_plan_prefix(
JOIN *join, uint idx,
41 table_map excluded_tables);
78 ulonglong bound_sj_equalities;
81 ulonglong handled_sj_equalities;
82 key_part_map loose_scan_keyparts;
87 uint max_loose_keypart;
93 uint quick_uses_applicable_index;
94 uint quick_max_loose_keypart;
97 uint best_loose_scan_key;
98 double best_loose_scan_cost;
99 double best_loose_scan_records;
100 Key_use *best_loose_scan_start_key;
102 uint best_max_loose_keypart;
106 try_loosescan(FALSE),
107 quick_uses_applicable_index(FALSE)
121 #ifdef COMPILE_FLAG_WERROR
122 bound_sj_equalities= 0;
123 quick_max_loose_keypart= 0;
124 best_loose_scan_key= 0;
125 best_loose_scan_records= 0;
126 best_max_loose_keypart= 0;
127 best_loose_scan_start_key= NULL;
131 void init(
JOIN_TAB *s, table_map remaining_tables,
132 bool in_dups_producing_range,
bool is_sjm_nest)
149 best_loose_scan_cost= DBL_MAX;
150 if (s->emb_sj_nest && !is_sjm_nest &&
151 s->emb_sj_nest->nested_join->sj_inner_exprs.elements <= 64 &&
152 ((remaining_tables & s->emb_sj_nest->sj_inner_tables) ==
153 s->emb_sj_nest->sj_inner_tables) &&
154 !in_dups_producing_range &&
157 (remaining_tables & s->emb_sj_nest->nested_join->
sj_depends_on) &&
158 s->join->thd->optimizer_switch_flag(OPTIMIZER_SWITCH_LOOSE_SCAN) &&
162 bound_sj_equalities= 0;
163 DBUG_PRINT(
"info", (
"Will try LooseScan scan"));
169 handled_sj_equalities=0;
170 loose_scan_keyparts= 0;
171 max_loose_keypart= 0;
172 part1_conds_met= FALSE;
175 void add_keyuse(table_map remaining_tables,
Key_use *keyuse)
177 if (try_loosescan && keyuse->
sj_pred_no != UINT_MAX)
185 bound_sj_equalities |= 1ULL << keyuse->
sj_pred_no;
189 handled_sj_equalities |= 1ULL << keyuse->
sj_pred_no;
190 loose_scan_keyparts |= ((key_part_map)1) << keyuse->
keypart;
191 set_if_bigger(max_loose_keypart, keyuse->
keypart);
196 bool have_a_case() {
return test(handled_sj_equalities); }
208 key_part_map bound_keyparts)
224 (handled_sj_equalities | bound_sj_equalities) ==
226 s->emb_sj_nest->nested_join->sj_inner_exprs.elements) &&
227 (
LOWER_BITS(key_part_map, max_loose_keypart+1) &
228 ~(bound_keyparts | loose_scan_keyparts)) == 0 &&
232 part1_conds_met= TRUE;
233 if (s->quick && s->quick->index == key &&
234 s->quick->get_type() == QUICK_SELECT_I::QS_TYPE_RANGE)
236 quick_uses_applicable_index= TRUE;
237 quick_max_loose_keypart= max_loose_keypart;
239 DBUG_PRINT(
"info", (
"Can use LooseScan scan"));
250 if (!(bound_keyparts & 1 ) &&
251 s->table->covering_keys.is_set(key))
253 DBUG_PRINT(
"info", (
"Can use full index scan for LooseScan"));
256 double records= rows2double(s->table->file->stats.records);
268 if ((rpc= s->table->key_info[key].
rec_per_key[max_loose_keypart]))
269 records= records / rpc;
272 if (read_time < best_loose_scan_cost)
274 best_loose_scan_key= key;
275 best_loose_scan_cost= read_time;
276 best_loose_scan_records= records;
277 best_max_loose_keypart= max_loose_keypart;
278 best_loose_scan_start_key= start_key;
301 if (part1_conds_met && read_time < best_loose_scan_cost)
304 best_loose_scan_key= key;
305 best_loose_scan_cost= read_time;
306 best_loose_scan_records= records;
307 best_max_loose_keypart= max_loose_keypart;
308 best_loose_scan_start_key= start_key;
315 if (quick_uses_applicable_index && idx == join->
const_tables &&
316 quick->read_time < best_loose_scan_cost)
318 best_loose_scan_key= quick->index;
319 best_loose_scan_cost= quick->read_time;
321 best_loose_scan_records= rows2double(quick->records);
322 best_max_loose_keypart= quick_max_loose_keypart;
323 best_loose_scan_start_key= NULL;
329 pos->read_time= best_loose_scan_cost;
330 if (best_loose_scan_cost != DBL_MAX)
332 pos->records_read= best_loose_scan_records;
333 pos->key= best_loose_scan_start_key;
334 pos->loosescan_key= best_loose_scan_key;
335 pos->loosescan_parts= best_max_loose_keypart + 1;
336 pos->use_join_buffer= FALSE;
339 DBUG_PRINT(
"info", (
"Produced a LooseScan plan, key %s, %s",
340 tab->table->key_info[best_loose_scan_key].
name,
341 best_loose_scan_start_key?
"(ref access)":
342 "(range/index access)"));
349 max_part_bit(key_part_map bits)
352 for (found=0; bits & 1 ; found++,bits>>=1) ;
357 cache_record_length(
JOIN *join,uint idx)
363 for (pos=join->best_ref+join->
const_tables,end=join->best_ref+idx ;
368 if (!join_tab->used_fieldlength)
370 length+=join_tab->used_fieldlength;
399 void Optimize_table_order::best_access_path(
401 table_map remaining_tables,
409 uint best_max_key_part= 0;
410 bool found_constraint=
false;
411 double best= DBL_MAX;
412 double best_time= DBL_MAX;
413 double records= DBL_MAX;
414 table_map best_ref_depends_map= 0;
416 bool best_uses_jbuf=
false;
419 status_var_increment(thd->status_var.last_query_partial_plans);
427 disable_jbuf= disable_jbuf ||
429 !thd->optimizer_switch_flag(OPTIMIZER_SWITCH_BNL);
432 DBUG_ENTER(
"Optimize_table_order::best_access_path");
451 const bool in_dups_producing_range=
454 (pos == (join->positions + idx) ?
457 loose_scan_opt.init(s, remaining_tables, in_dups_producing_range,
458 emb_sjm_nest != NULL);
465 if (unlikely(s->
keyuse != NULL))
468 double best_records= DBL_MAX;
475 key_part_map found_part= 0;
476 table_map found_ref= 0;
477 const uint key= keyuse->
key;
478 uint max_key_part= 0;
479 KEY *
const keyinfo= table->key_info+key;
480 const bool ft_key= (keyuse->
keypart == FT_KEYPART);
482 key_part_map const_part= 0;
484 key_part_map ref_or_null_part= 0;
487 Key_use *
const start_key= keyuse;
489 loose_scan_opt.next_ref_key();
490 DBUG_PRINT(
"info", (
"Considering ref access on key %s",
493 trace_access_idx.add_alnum(
"access_type",
"ref").
494 add_utf8(
"index", keyinfo->
name);
497 while (keyuse->
table == table && keyuse->
key == key)
499 const uint keypart= keyuse->
keypart;
500 table_map best_part_found_ref= 0;
501 double best_prev_record_reads= DBL_MAX;
504 for ( ; keyuse->
table == table && keyuse->
key == key &&
505 keyuse->
keypart == keypart ; ++keyuse)
520 !(ref_or_null_part && (keyuse->
optimize &
521 KEY_OPTIMIZE_REF_OR_NULL)))
527 double tmp2= prev_record_reads(join, idx, (found_ref |
529 if (tmp2 < best_prev_record_reads)
532 best_prev_record_reads= tmp2;
540 if (keyuse->
optimize & KEY_OPTIMIZE_REF_OR_NULL)
543 loose_scan_opt.add_keyuse(remaining_tables, keyuse);
545 found_ref|= best_part_found_ref;
551 if (!found_part && !ft_key && !loose_scan_opt.have_a_case())
553 trace_access_idx.add(
"usable",
false);
554 goto done_with_index;
569 tmp= prev_record_reads(join, idx, found_ref);
574 found_constraint=
test(found_part);
581 max_key_part= (uint) ~0;
582 if ((keyinfo->
flags & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME)
584 tmp = prev_record_reads(join, idx, found_ref);
608 if (table->quick_keys.is_set(key))
609 records= (
double) table->quick_rows[key];
613 records= (double) s->records/rec;
621 ((double) s->records / (
double) rec *
623 ((double) (table->s->max_key_length-keyinfo->
key_length) /
624 (double) table->s->max_key_length)));
638 if (table->quick_keys.is_set(key) &&
640 (((key_part_map)1 << table->quick_key_parts[key])-1)) ==
641 (((key_part_map)1 << table->quick_key_parts[key])-1) &&
642 table->quick_n_ranges[key] == 1 &&
643 records > (
double) table->quick_rows[key])
645 records= (double) table->quick_rows[key];
650 set_if_smaller(tmp, (
double) thd->variables.max_seeks_for_key);
651 if (table->covering_keys.is_set(key))
657 tmp= record_count*min(tmp,s->worst_seeks);
667 if ((found_part & 1) &&
668 (!(table->file->index_flags(key, 0, 0) & HA_ONLY_WHOLE_INDEX) ||
672 max_key_part= max_part_bit(found_part);
712 if (table->quick_keys.is_set(key) && !found_ref &&
713 table->quick_key_parts[key] == max_key_part &&
714 table->quick_n_ranges[key] == 1+
test(ref_or_null_part))
716 tmp= records= (double) table->quick_rows[key];
721 if ((records= keyinfo->
rec_per_key[max_key_part-1]))
747 if (!found_ref && table->quick_keys.is_set(key) &&
748 table->quick_key_parts[key] > max_key_part &&
749 records < (double)table->quick_rows[key])
750 records= (double)table->quick_rows[key];
771 if (!(rec_per_key=(
double)
773 rec_per_key=(double) s->records/rec+1;
777 else if (rec_per_key/(
double) s->records >= 0.01)
781 double a=s->records*0.01;
783 tmp= (max_key_part * (rec_per_key - a) +
788 set_if_bigger(tmp,1.0);
790 records = (ulong) tmp;
793 if (ref_or_null_part)
812 if (table->quick_keys.is_set(key) &&
813 table->quick_key_parts[key] <= max_key_part &&
815 ((key_part_map)1 << table->quick_key_parts[key]) &&
816 table->quick_n_ranges[key] == 1 +
test(ref_or_null_part &
818 records > (double) table->quick_rows[key])
820 tmp= records= (double) table->quick_rows[key];
825 set_if_smaller(tmp, (
double) thd->variables.max_seeks_for_key);
826 if (table->covering_keys.is_set(key))
832 tmp= record_count * min(tmp,s->worst_seeks);
846 trace_access_idx.add(
"rows", records).add(
"cost", idx_time);
847 if (idx_time < best_time)
851 best_records= records;
853 best_max_key_part= max_key_part;
854 best_ref_depends_map= found_ref;
858 trace_access_idx.add(
"chosen", best_key == start_key);
860 records= best_records;
895 if (!(records >= s->found_records || best > s->read_time))
898 trace_access_scan.add_alnum(
"access_type", s->quick ?
"range" :
"scan").
899 add(
"cost", s->read_time + s->found_records * ROW_EVALUATE_COST).
900 add(
"rows", s->found_records).
901 add_alnum(
"cause",
"cost");
903 goto skip_table_scan;
906 if ((s->quick && best_key && s->quick->index == best_key->
key &&
907 best_max_key_part >= s->table->quick_key_parts[best_key->
key]))
909 trace_access_scan.add_alnum(
"access_type",
"range").
910 add_alnum(
"cause",
"heuristic_index_cheaper");
911 goto skip_table_scan;
914 if ((s->table->file->
ha_table_flags() & HA_TABLE_SCAN_ON_INDEX) &&
915 !s->table->covering_keys.is_clear_all() && best_key &&
917 (s->quick->get_type() == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT &&
918 best < s->quick->read_time)))
920 trace_access_scan.add_alnum(
"access_type", s->quick ?
"range" :
"scan").
921 add_alnum(
"cause",
"covering_index_better_than_full_scan");
922 goto skip_table_scan;
925 if ((s->table->force_index && best_key && !s->quick))
927 trace_access_scan.add_alnum(
"access_type",
"scan").
928 add_alnum(
"cause",
"force_index");
929 goto skip_table_scan;
933 ha_rows rnd_records= s->found_records;
943 if (found_constraint)
944 rnd_records-= rnd_records/4;
950 if (s->table->quick_condition_rows != s->found_records)
951 rnd_records= s->table->quick_condition_rows;
961 trace_access_scan.add_alnum(
"access_type",
"range");
972 (s->quick->read_time +
973 (s->found_records - rnd_records) * ROW_EVALUATE_COST);
975 loose_scan_opt.check_range_access(join, idx, s->quick);
979 trace_access_scan.add_alnum(
"access_type",
"scan");
981 if (s->table->force_index && !best_key)
982 tmp= s->table->file->
read_time(s->ref.
key, 1, s->records);
984 tmp= s->table->file->scan_time();
994 (tmp + (s->records - rnd_records) * ROW_EVALUATE_COST);
998 trace_access_scan.add(
"using_join_cache",
true);
1004 tmp*= (1.0 + ((double) cache_record_length(join,idx) *
1006 (double) thd->variables.join_buff_size));
1014 tmp+= (s->records - rnd_records) * ROW_EVALUATE_COST;
1018 const double scan_cost=
1019 tmp + (record_count * ROW_EVALUATE_COST * rnd_records);
1021 trace_access_scan.add(
"rows", rows2double(rnd_records)).
1022 add(
"cost", scan_cost);
1028 if (best == DBL_MAX ||
1029 (scan_cost < best + (record_count * ROW_EVALUATE_COST * records)))
1036 records= rows2double(rnd_records);
1039 best_ref_depends_map= 0;
1040 best_uses_jbuf=
test(!disable_jbuf);
1045 trace_access_scan.add(
"chosen", best_key == NULL);
1048 pos->records_read= records;
1049 pos->read_time= best;
1052 pos->ref_depend_map= best_ref_depends_map;
1053 pos->loosescan_key= MAX_KEY;
1054 pos->use_join_buffer= best_uses_jbuf;
1056 loose_scan_opt.save_to_position(s, loose_scan_pos);
1060 s->table == join->sort_by_table &&
1061 join->
unit->select_limit_cnt >= records)
1063 trace_access_scan.add(
"use_tmp_table",
true);
1064 join->sort_by_table= (
TABLE*) 1;
1090 DBUG_ENTER(
"Optimize_table_order::choose_table_order");
1095 memcpy(join->best_positions, join->positions,
1104 const bool straight_join=
test(join->select_options & SELECT_STRAIGHT_JOIN);
1105 table_map join_tables;
1113 join->best_ref + join->
tables,
1115 join_tables= emb_sjm_nest->sj_inner_tables;
1129 join->best_ref + join->
tables,
1133 join->best_ref + join->
tables,
1141 trace_plan(&join->thd->opt_trace,
"considered_execution_plans",
1142 Opt_trace_context::GREEDY_SEARCH);
1144 optimize_straight_join(join_tables);
1147 if (greedy_search(join_tables))
1156 if (fix_semijoin_strategies())
1196 uint Optimize_table_order::determine_search_depth(uint search_depth,
1199 if (search_depth > 0)
1200 return search_depth;
1202 const uint max_tables_for_exhaustive_opt= 7;
1204 if (table_count <= max_tables_for_exhaustive_opt)
1205 search_depth= table_count+1;
1211 search_depth= max_tables_for_exhaustive_opt;
1213 return search_depth;
1238 void Optimize_table_order::optimize_straight_join(table_map join_tables)
1242 double record_count= 1.0;
1243 double read_time= 0.0;
1246 for (
JOIN_TAB **pos= join->best_ref + idx ; (s= *pos) ; pos++)
1248 POSITION *
const position= join->positions + idx;
1250 if (unlikely(trace->is_started()))
1252 trace_plan_prefix(join, idx, excluded_tables);
1253 trace_table.add_utf8_table(s->table);
1260 DBUG_ASSERT(!check_interleaving_with_nj(s));
1263 best_access_path(s, join_tables, idx,
false, record_count,
1264 position, &loose_scan_pos);
1267 record_count*= position->records_read;
1268 read_time+= position->read_time;
1270 position->set_prefix_costs(read_time, record_count);
1274 advance_sj_state(join_tables, s, idx, &record_count, &read_time,
1279 trace_table.add(
"cost_for_plan", read_time).
1280 add(
"rows_for_plan", record_count);
1281 join_tables&= ~(s->table->map);
1285 if (join->sort_by_table &&
1286 join->sort_by_table != join->positions[join->
const_tables].table->table)
1287 read_time+= record_count;
1289 memcpy(join->best_positions, join->positions,
sizeof(
POSITION)*idx);
1332 semijoin_order_allows_materialization(
const JOIN *join,
1333 table_map remaining_tables,
1336 DBUG_ASSERT(!(remaining_tables & tab->table->map));
1342 const TABLE_LIST *emb_sj_nest= tab->emb_sj_nest;
1344 !emb_sj_nest->nested_join->sjm.
positions ||
1345 (remaining_tables & emb_sj_nest->sj_inner_tables))
1352 const uint n_tables= my_count_bits(emb_sj_nest->sj_inner_tables);
1353 for (uint
i= 1;
i < n_tables ;
i++)
1355 if (join->positions[idx -
i].table->emb_sj_nest != emb_sj_nest)
1363 if ((remaining_tables & emb_sj_nest->nested_join->
sj_depends_on) ||
1367 return SJ_OPT_MATERIALIZE_SCAN;
1370 return SJ_OPT_MATERIALIZE_LOOKUP;
1454 bool Optimize_table_order::greedy_search(table_map remaining_tables)
1456 double record_count= 1.0;
1457 double read_time= 0.0;
1462 DBUG_ENTER(
"Optimize_table_order::greedy_search");
1465 const uint n_tables= my_count_bits(remaining_tables);
1468 uint size_remain= n_tables;
1474 if (best_extension_by_limited_search(remaining_tables, idx,
1475 record_count, read_time,
1484 if (size_remain <= search_depth)
1490 DBUG_EXECUTE(
"opt", print_plan(join, n_tables, record_count, read_time,
1491 read_time,
"optimal"););
1496 best_pos= join->best_positions[idx];
1497 best_table= best_pos.table;
1503 join->positions[idx]= best_pos;
1517 bool is_interleave_error __attribute__((unused))=
1518 check_interleaving_with_nj (best_table);
1520 DBUG_ASSERT(!is_interleave_error);
1524 JOIN_TAB *pos= join->best_ref[best_idx];
1525 while (pos && best_table != pos)
1526 pos= join->best_ref[++best_idx];
1527 DBUG_ASSERT((pos != NULL));
1533 memmove(join->best_ref + idx + 1, join->best_ref + idx,
1534 sizeof(
JOIN_TAB*) * (best_idx - idx));
1535 join->best_ref[idx]= best_table;
1538 record_count*= join->positions[idx].records_read;
1539 read_time+= join->positions[idx].read_time
1542 remaining_tables&= ~(best_table->table->map);
1546 DBUG_EXECUTE(
"opt", print_plan(join, idx, record_count, read_time,
1547 read_time,
"extended"););
1575 void get_partial_join_cost(
JOIN *join, uint n_tables,
double *read_time_arg,
1576 double *record_count_arg)
1578 double record_count= 1;
1579 double read_time= 0.0;
1580 for (uint
i= join->
const_tables; i < n_tables + join->const_tables ;
i++)
1582 if (join->best_positions[
i].records_read)
1584 record_count *= join->best_positions[
i].records_read;
1585 read_time += join->best_positions[
i].read_time
1589 *read_time_arg= read_time;
1590 *record_count_arg= record_count;
1608 void Optimize_table_order::consider_plan(uint idx,
1609 double record_count,
1618 if (join->sort_by_table &&
1619 join->sort_by_table !=
1622 read_time+= record_count;
1623 trace_obj->add(
"sort_cost", record_count).
1624 add(
"new_cost_for_plan", read_time);
1627 const bool chosen= read_time < join->
best_read;
1628 trace_obj->add(
"chosen", chosen);
1631 memcpy((uchar*) join->best_positions, (uchar*) join->positions,
1643 DBUG_EXECUTE(
"opt", print_plan(join, idx+1,
1775 bool Optimize_table_order::best_extension_by_limited_search(
1776 table_map remaining_tables,
1778 double record_count,
1780 uint current_search_depth)
1782 DBUG_ENTER(
"Optimize_table_order::best_extension_by_limited_search");
1784 DBUG_EXECUTE_IF(
"bug13820776_2", thd->killed= THD::KILL_QUERY;);
1793 double best_record_count= DBL_MAX;
1794 double best_read_time= DBL_MAX;
1796 DBUG_EXECUTE(
"opt", print_plan(join, idx, record_count, read_time, read_time,
1803 const bool has_sj= !(join->
select_lex->sj_nests.is_empty() || emb_sjm_nest);
1811 table_map eq_ref_extended(0);
1815 memcpy(saved_refs, join->best_ref + idx,
1818 for (
JOIN_TAB **pos= join->best_ref + idx; *pos; pos++)
1821 const table_map real_table_bit= s->table->map;
1828 swap_variables(
JOIN_TAB*, join->best_ref[idx], *pos);
1830 if ((remaining_tables & real_table_bit) &&
1831 !(eq_ref_extended & real_table_bit) &&
1833 (!idx || !check_interleaving_with_nj(s)))
1835 double current_record_count, current_read_time;
1837 if (unlikely(trace->is_started()))
1839 trace_plan_prefix(join, idx, excluded_tables);
1840 trace_one_table.add_utf8_table(s->table);
1842 POSITION *
const position= join->positions + idx;
1845 DBUG_ASSERT(emb_sjm_nest == NULL || emb_sjm_nest == s->emb_sj_nest);
1848 best_access_path(s, remaining_tables, idx,
false, record_count,
1849 position, &loose_scan_pos);
1852 current_record_count= record_count * position->records_read;
1853 current_read_time= read_time
1854 + position->read_time
1856 position->set_prefix_costs(current_read_time, current_record_count);
1858 trace_one_table.add(
"cost_for_plan", current_read_time).
1859 add(
"rows_for_plan", current_record_count);
1871 advance_sj_state(remaining_tables, s, idx,
1872 ¤t_record_count, ¤t_read_time,
1879 if (current_read_time >= join->
best_read)
1881 DBUG_EXECUTE(
"opt", print_plan(join, idx+1,
1882 current_record_count,
1886 trace_one_table.add(
"pruned_by_cost",
true);
1887 backout_nj_state(remaining_tables, s);
1895 if (prune_level == 1)
1897 if (best_record_count > current_record_count ||
1898 best_read_time > current_read_time ||
1900 s->table == join->sort_by_table))
1902 if (best_record_count >= current_record_count &&
1903 best_read_time >= current_read_time &&
1906 position->records_read < 2.0))
1908 best_record_count= current_record_count;
1909 best_read_time= current_read_time;
1914 DBUG_EXECUTE(
"opt", print_plan(join, idx+1,
1915 current_record_count,
1918 "pruned_by_heuristic"););
1919 trace_one_table.add(
"pruned_by_heuristic",
true);
1920 backout_nj_state(remaining_tables, s);
1925 const table_map remaining_tables_after=
1926 (remaining_tables & ~real_table_bit);
1927 if ((current_search_depth > 1) && remaining_tables_after)
1937 if (prune_level == 1 &&
1938 position->key != NULL &&
1939 position->records_read <= 1.0)
1948 if (eq_ref_extended == (table_map)0)
1952 eq_ref_extended= real_table_bit |
1953 eq_ref_extension_by_limited_search(
1954 remaining_tables_after,
1956 current_record_count,
1958 current_search_depth - 1);
1959 if (eq_ref_extended == ~(table_map)0)
1962 backout_nj_state(remaining_tables, s);
1964 if (eq_ref_extended == remaining_tables)
1971 DBUG_EXECUTE(
"opt", print_plan(join, idx+1,
1972 current_record_count,
1975 "pruned_by_eq_ref_heuristic"););
1976 trace_one_table.add(
"pruned_by_eq_ref_heuristic",
true);
1977 backout_nj_state(remaining_tables, s);
1984 if (best_extension_by_limited_search(remaining_tables_after,
1986 current_record_count,
1988 current_search_depth - 1))
1993 consider_plan(idx, current_record_count, current_read_time,
1999 DBUG_ASSERT((remaining_tables_after != 0) ||
2000 ((cur_embedding_map == 0) &&
2003 backout_nj_state(remaining_tables, s);
2009 memcpy(join->best_ref + idx, saved_refs,
2128 table_map Optimize_table_order::eq_ref_extension_by_limited_search(
2129 table_map remaining_tables,
2131 double record_count,
2133 uint current_search_depth)
2135 DBUG_ENTER(
"Optimize_table_order::eq_ref_extension_by_limited_search");
2137 if (remaining_tables == 0)
2140 const bool has_sj= !(join->
select_lex->sj_nests.is_empty() || emb_sjm_nest);
2149 table_map eq_ref_ext(0);
2153 memcpy(saved_refs, join->best_ref + idx,
2156 for (
JOIN_TAB **pos= join->best_ref + idx ; (s= *pos) ; pos++)
2158 const table_map real_table_bit= s->table->map;
2165 swap_variables(
JOIN_TAB*, join->best_ref[idx], *pos);
2175 (remaining_tables & real_table_bit) &&
2177 (!idx || !check_interleaving_with_nj(s)))
2180 if (unlikely(trace->is_started()))
2182 trace_plan_prefix(join, idx, excluded_tables);
2183 trace_one_table.add_utf8_table(s->table);
2185 POSITION *
const position= join->positions + idx;
2188 DBUG_ASSERT(emb_sjm_nest == NULL || emb_sjm_nest == s->emb_sj_nest);
2190 best_access_path(s, remaining_tables, idx,
false, record_count,
2191 position, &loose_scan_pos);
2201 const bool added_to_eq_ref_extension=
2203 position->read_time == (position-1)->read_time &&
2204 position->records_read == (position-1)->records_read;
2205 trace_one_table.add(
"added_to_eq_ref_extension",
2206 added_to_eq_ref_extension);
2207 if (added_to_eq_ref_extension)
2209 double current_record_count, current_read_time;
2212 current_record_count= record_count * position->records_read;
2213 current_read_time= read_time
2214 + position->read_time
2216 position->set_prefix_costs(current_read_time, current_record_count);
2218 trace_one_table.add(
"cost_for_plan", current_read_time).
2219 add(
"rows_for_plan", current_record_count);
2229 advance_sj_state(remaining_tables, s, idx,
2230 ¤t_record_count, ¤t_read_time,
2237 if (current_read_time >= join->
best_read)
2239 DBUG_EXECUTE(
"opt", print_plan(join, idx+1,
2240 current_record_count,
2244 trace_one_table.add(
"pruned_by_cost",
true);
2245 backout_nj_state(remaining_tables, s);
2249 eq_ref_ext= real_table_bit;
2250 const table_map remaining_tables_after=
2251 (remaining_tables & ~real_table_bit);
2252 if ((current_search_depth > 1) && remaining_tables_after)
2254 DBUG_EXECUTE(
"opt", print_plan(join, idx + 1,
2255 current_record_count,
2258 "EQ_REF_extension"););
2263 eq_ref_extension_by_limited_search(remaining_tables_after,
2265 current_record_count,
2267 current_search_depth - 1);
2271 consider_plan(idx, current_record_count, current_read_time,
2273 DBUG_ASSERT((remaining_tables_after != 0) ||
2274 ((cur_embedding_map == 0) &&
2277 backout_nj_state(remaining_tables, s);
2278 memcpy(join->best_ref + idx, saved_refs,
2280 DBUG_RETURN(eq_ref_ext);
2283 backout_nj_state(remaining_tables, s);
2287 memcpy(join->best_ref + idx, saved_refs,
sizeof(
JOIN_TAB*) * (join->
tables-idx));
2293 DBUG_ASSERT(!eq_ref_ext);
2294 if (best_extension_by_limited_search(remaining_tables,
2298 current_search_depth))
2299 DBUG_RETURN(~(table_map)0);
2301 DBUG_RETURN(eq_ref_ext);
2357 prev_record_reads(
JOIN *join, uint idx, table_map found_ref)
2360 POSITION *pos_end= join->positions - 1;
2361 for (
POSITION *pos= join->positions + idx - 1; pos != pos_end; pos--)
2363 if (pos->table->table->map & found_ref)
2365 found_ref|= pos->ref_depend_map;
2382 if (pos->records_read > DBL_EPSILON)
2383 found*= pos->records_read;
2430 bool Optimize_table_order::fix_semijoin_strategies()
2432 table_map remaining_tables= 0;
2433 table_map handled_tables= 0;
2435 DBUG_ENTER(
"Optimize_table_order::fix_semijoin_strategies");
2442 for (uint tableno= join->
tables - 1;
2446 POSITION *
const pos= join->best_positions + tableno;
2448 if ((handled_tables & pos->table->table->map) ||
2449 pos->sj_strategy == SJ_OPT_NONE)
2451 remaining_tables|= pos->table->table->map;
2457 if (pos->sj_strategy == SJ_OPT_MATERIALIZE_LOOKUP)
2459 TABLE_LIST *
const sjm_nest= pos->table->emb_sj_nest;
2460 const uint table_count= my_count_bits(sjm_nest->sj_inner_tables);
2477 memcpy(pos - table_count + 1, sjm_nest->nested_join->sjm.
positions,
2479 first= tableno - table_count + 1;
2480 join->best_positions[first].n_sj_tables= table_count;
2481 join->best_positions[first].sj_strategy= SJ_OPT_MATERIALIZE_LOOKUP;
2484 trace_final_strategy.add_alnum(
"final_semijoin_strategy",
2485 "MaterializeLookup");
2487 else if (pos->sj_strategy == SJ_OPT_MATERIALIZE_SCAN)
2489 const uint last_inner= pos->sjm_scan_last_inner;
2491 (join->best_positions + last_inner)->table->emb_sj_nest;
2492 const uint table_count= my_count_bits(sjm_nest->sj_inner_tables);
2493 first= last_inner - table_count + 1;
2494 DBUG_ASSERT((join->best_positions + first)->table->emb_sj_nest ==
2496 memcpy(join->best_positions + first,
2499 join->best_positions[first].sj_strategy= SJ_OPT_MATERIALIZE_SCAN;
2500 join->best_positions[first].n_sj_tables= table_count;
2503 trace_final_strategy.add_alnum(
"final_semijoin_strategy",
2506 double rowcount, cost;
2507 semijoin_mat_scan_access_paths(last_inner, tableno,
2508 remaining_tables, sjm_nest,
true,
2512 else if (pos->sj_strategy == SJ_OPT_FIRST_MATCH)
2514 first= pos->first_firstmatch_table;
2515 join->best_positions[first].sj_strategy= SJ_OPT_FIRST_MATCH;
2516 join->best_positions[first].n_sj_tables= tableno - first + 1;
2519 trace_final_strategy.add_alnum(
"final_semijoin_strategy",
"FirstMatch");
2522 double rowcount, cost;
2523 (void)semijoin_firstmatch_loosescan_access_paths(first, tableno,
2524 remaining_tables,
false,
true,
2527 else if (pos->sj_strategy == SJ_OPT_LOOSE_SCAN)
2529 first= pos->first_loosescan_table;
2532 trace_final_strategy.add_alnum(
"final_semijoin_strategy",
"LooseScan");
2535 double rowcount, cost;
2536 (void)semijoin_firstmatch_loosescan_access_paths(first, tableno,
2537 remaining_tables,
true,
true,
2540 POSITION *
const first_pos= join->best_positions + first;
2541 first_pos->sj_strategy= SJ_OPT_LOOSE_SCAN;
2542 first_pos->n_sj_tables=
2543 my_count_bits(first_pos->table->emb_sj_nest->sj_inner_tables);
2545 else if (pos->sj_strategy == SJ_OPT_DUPS_WEEDOUT)
2551 first= pos->first_dupsweedout_table;
2552 join->best_positions[first].sj_strategy= SJ_OPT_DUPS_WEEDOUT;
2553 join->best_positions[first].n_sj_tables= tableno - first + 1;
2556 trace_final_strategy.add_alnum(
"final_semijoin_strategy",
2557 "DuplicateWeedout");
2560 for (uint
i= first;
i <= tableno;
i++)
2567 join->best_positions[
i].sj_strategy= SJ_OPT_NONE;
2568 handled_tables|= join->best_positions[
i].table->table->map;
2571 remaining_tables |= pos->table->table->map;
2671 bool Optimize_table_order::check_interleaving_with_nj(
JOIN_TAB *tab)
2673 if (cur_embedding_map & ~tab->embedding_map)
2681 const TABLE_LIST *next_emb= tab->table->pos_in_table_list->embedding;
2686 for (; next_emb != emb_sjm_nest; next_emb= next_emb->embedding)
2689 if (!next_emb->join_cond())
2693 cur_embedding_map |= next_emb->nested_join->
nj_map;
2702 cur_embedding_map &= ~next_emb->nested_join->
nj_map;
2751 bool Optimize_table_order::semijoin_firstmatch_loosescan_access_paths(
2752 uint first_tab, uint last_tab, table_map remaining_tables,
2753 bool loosescan,
bool final,
2754 double *newcount,
double *newcost)
2757 "Optimize_table_order::semijoin_firstmatch_loosescan_access_paths");
2760 double outer_fanout= 1.0;
2761 double inner_fanout= 1.0;
2766 POSITION *
const positions=
final ? join->best_positions : join->positions;
2775 cost= positions[first_tab - 1].prefix_cost.
total_cost();
2776 rowcount= positions[first_tab - 1].prefix_record_count;
2779 uint table_count= 0;
2780 uint no_jbuf_before;
2781 for (uint
i= first_tab;
i <= last_tab;
i++)
2783 remaining_tables|= positions[
i].table->table->map;
2784 if (positions[
i].table->emb_sj_nest)
2790 for (no_jbuf_before= last_tab; no_jbuf_before > first_tab; no_jbuf_before--)
2792 if (positions[no_jbuf_before].table->emb_sj_nest != NULL)
2800 no_jbuf_before= (table_count > 1) ? last_tab + 1 : first_tab;
2804 for (uint
i= first_tab;
i <= last_tab;
i++)
2806 JOIN_TAB *
const tab= positions[
i].table;
2807 POSITION regular_pos, loose_scan_pos;
2808 POSITION *
const dst_pos=
final ? positions +
i : ®ular_pos;
2814 if ((
i == first_tab && loosescan) || positions[
i].use_join_buffer)
2817 trace_one_table.add_utf8_table(tab->table);
2820 best_access_path(tab, remaining_tables,
i,
2822 rowcount * inner_fanout * outer_fanout,
2823 dst_pos, &loose_scan_pos);
2824 if (
i == first_tab && loosescan)
2826 *dst_pos= loose_scan_pos;
2827 const double rows= rowcount * dst_pos->records_read;
2828 dst_pos->set_prefix_costs(cost + dst_pos->read_time +
2829 rows * ROW_EVALUATE_COST,
2841 if (pos->read_time == DBL_MAX)
2843 DBUG_ASSERT(loosescan && !
final);
2847 remaining_tables&= ~tab->table->map;
2849 if (tab->emb_sj_nest)
2850 inner_fanout*= pos->records_read;
2852 outer_fanout*= pos->records_read;
2854 cost+= pos->read_time +
2858 *newcount= rowcount * outer_fanout;
2888 void Optimize_table_order::semijoin_mat_scan_access_paths(
2889 uint last_inner_tab, uint last_outer_tab,
2890 table_map remaining_tables,
TABLE_LIST *sjm_nest,
bool final,
2891 double *newcount,
double *newcost)
2893 DBUG_ENTER(
"Optimize_table_order::semijoin_mat_scan_access_paths");
2901 POSITION *
const positions=
final ? join->best_positions : join->positions;
2902 const uint inner_count= my_count_bits(sjm_nest->sj_inner_tables);
2905 const uint first_inner= last_inner_tab + 1 - inner_count;
2913 rowcount= positions[first_inner - 1].prefix_record_count;
2914 cost= positions[first_inner - 1].prefix_cost.
total_cost();
2921 for (uint i= last_inner_tab + 1; i <= last_outer_tab; i++)
2922 remaining_tables|= positions[i].table->table->map;
2930 double outer_fanout= 1.0;
2932 for (uint i= last_inner_tab + 1; i <= last_outer_tab; i++)
2935 JOIN_TAB *
const tab= positions[
i].table;
2936 trace_one_table.add_utf8_table(tab->table);
2938 POSITION *
const dst_pos=
final ? positions + i : ®ular_pos;
2939 best_access_path(tab, remaining_tables, i,
false,
2940 rowcount * inner_fanout * outer_fanout, dst_pos, &dummy);
2941 remaining_tables&= ~tab->table->map;
2942 outer_fanout*= dst_pos->records_read;
2943 cost+= dst_pos->read_time +
2947 *newcount= rowcount * outer_fanout;
2970 void Optimize_table_order::semijoin_mat_lookup_access_paths(
2972 double *newcount,
double *newcost)
2974 DBUG_ENTER(
"Optimize_table_order::semijoin_mat_lookup_access_paths");
2976 const uint inner_count= my_count_bits(sjm_nest->sj_inner_tables);
2977 double rowcount, cost;
2979 const uint first_inner= last_inner + 1 - inner_count;
2987 cost= join->positions[first_inner - 1].prefix_cost.
total_cost();
2988 rowcount= join->positions[first_inner - 1].prefix_record_count;
2994 *newcount= rowcount;
3027 void Optimize_table_order::semijoin_dupsweedout_access_paths(
3028 uint first_tab, uint last_tab,
3029 table_map remaining_tables,
3030 double *newcount,
double *newcost)
3032 DBUG_ENTER(
"Optimize_table_order::semijoin_dupsweedout_access_paths");
3034 double cost, rowcount;
3035 double inner_fanout= 1.0;
3036 double outer_fanout= 1.0;
3046 cost= join->positions[first_tab - 1].prefix_cost.
total_cost();
3047 rowcount= join->positions[first_tab - 1].prefix_record_count;
3071 for (uint j= first_tab; j <= last_tab; j++)
3073 const POSITION *
const p= join->positions + j;
3074 if (p->table->emb_sj_nest)
3076 inner_fanout*= p->records_read;
3080 outer_fanout*= p->records_read;
3084 cost+= p->read_time +
3096 double one_lookup_cost, create_cost;
3097 if (outer_fanout * rowsize > thd->variables.max_heap_table_size)
3099 one_lookup_cost= DISK_TEMPTABLE_ROW_COST;
3100 create_cost= DISK_TEMPTABLE_CREATE_COST;
3104 one_lookup_cost= HEAP_TEMPTABLE_ROW_COST;
3105 create_cost= HEAP_TEMPTABLE_CREATE_COST;
3107 const double write_cost= rowcount * outer_fanout * one_lookup_cost;
3108 const double full_lookup_cost= write_cost * inner_fanout;
3109 cost+= create_cost + write_cost + full_lookup_cost;
3111 *newcount= rowcount * outer_fanout;
3177 void Optimize_table_order::advance_sj_state(
3178 table_map remaining_tables,
3179 const JOIN_TAB *new_join_tab, uint idx,
3180 double *current_rowcount,
double *current_cost,
3184 TABLE_LIST *
const emb_sj_nest= new_join_tab->emb_sj_nest;
3185 POSITION *
const pos= join->positions + idx;
3186 uint sj_strategy= SJ_OPT_NONE;
3194 DBUG_ASSERT(emb_sjm_nest == NULL);
3197 remaining_tables &= ~new_join_tab->table->map;
3199 DBUG_ENTER(
"Optimize_table_order::advance_sj_state");
3209 pos->dupsweedout_tables= 0;
3210 pos->sjm_scan_need_tables= 0;
3211 LINT_INIT(pos->sjm_scan_last_inner);
3218 pos->first_firstmatch_table= pos[-1].first_firstmatch_table;
3219 pos->first_firstmatch_rtbl= pos[-1].first_firstmatch_rtbl;
3220 pos->firstmatch_need_tables= pos[-1].firstmatch_need_tables;
3223 pos->first_loosescan_table=
3224 (pos[-1].sj_strategy == SJ_OPT_LOOSE_SCAN) ?
3226 pos->loosescan_need_tables= pos[-1].loosescan_need_tables;
3229 pos->sjm_scan_need_tables=
3230 (pos[-1].sj_strategy == SJ_OPT_MATERIALIZE_SCAN) ?
3231 0 : pos[-1].sjm_scan_need_tables;
3232 pos->sjm_scan_last_inner= pos[-1].sjm_scan_last_inner;
3235 pos->dupsweedout_tables= pos[-1].dupsweedout_tables;
3236 pos->first_dupsweedout_table= pos[-1].first_dupsweedout_table;
3239 table_map handled_by_fm_or_ls= 0;
3260 thd->optimizer_switch_flag(OPTIMIZER_SWITCH_FIRSTMATCH))
3262 const table_map outer_corr_tables= emb_sj_nest->nested_join->
sj_depends_on;
3263 const table_map sj_inner_tables= emb_sj_nest->sj_inner_tables;
3275 !(remaining_tables & outer_corr_tables))
3278 pos->first_firstmatch_table= idx;
3279 pos->firstmatch_need_tables= 0;
3280 pos->first_firstmatch_rtbl= remaining_tables;
3282 DBUG_ASSERT(sj_inner_tables ==
3283 ((remaining_tables | new_join_tab->table->map) &
3287 if (pos->first_firstmatch_table !=
MAX_TABLES)
3290 pos->firstmatch_need_tables|= sj_inner_tables;
3292 if (outer_corr_tables & pos->first_firstmatch_rtbl)
3300 else if (!(pos->firstmatch_need_tables & remaining_tables))
3303 double cost, rowcount;
3306 trace_one_strategy.add_alnum(
"strategy",
"FirstMatch");
3307 (void)semijoin_firstmatch_loosescan_access_paths(
3308 pos->first_firstmatch_table, idx,
3309 remaining_tables,
false,
false,
3320 sj_strategy= SJ_OPT_FIRST_MATCH;
3321 *current_cost= cost;
3322 *current_rowcount= rowcount;
3323 trace_one_strategy.add(
"cost", *current_cost).
3324 add(
"rows", *current_rowcount);
3325 handled_by_fm_or_ls= pos->firstmatch_need_tables;
3327 trace_one_strategy.add(
"chosen",
true);
3344 if (thd->optimizer_switch_flag(OPTIMIZER_SWITCH_LOOSE_SCAN))
3346 POSITION *
const first= join->positions+pos->first_loosescan_table;
3351 if (pos->first_loosescan_table !=
MAX_TABLES)
3353 if (first->table->emb_sj_nest->sj_inner_tables &
3354 (remaining_tables | new_join_tab->table->map))
3357 if (emb_sj_nest != first->table->emb_sj_nest)
3363 DBUG_ASSERT(emb_sj_nest != first->table->emb_sj_nest);
3364 if (emb_sj_nest != NULL)
3372 if (loose_scan_pos->read_time != DBL_MAX)
3374 pos->first_loosescan_table= idx;
3375 pos->loosescan_need_tables= emb_sj_nest->sj_inner_tables |
3379 if ((pos->first_loosescan_table !=
MAX_TABLES) &&
3380 !(remaining_tables & pos->loosescan_need_tables))
3388 double cost, rowcount;
3390 trace_one_strategy.add_alnum(
"strategy",
"LooseScan");
3396 if (semijoin_firstmatch_loosescan_access_paths(
3397 pos->first_loosescan_table, idx,
3398 remaining_tables,
true,
false,
3408 sj_strategy= SJ_OPT_LOOSE_SCAN;
3409 *current_cost= cost;
3410 *current_rowcount= rowcount;
3411 trace_one_strategy.add(
"cost", *current_cost).
3412 add(
"rows", *current_rowcount);
3413 handled_by_fm_or_ls= first->table->emb_sj_nest->sj_inner_tables;
3415 trace_one_strategy.add(
"chosen", sj_strategy == SJ_OPT_LOOSE_SCAN);
3425 const int sjm_strategy=
3426 semijoin_order_allows_materialization(join, remaining_tables,
3428 if (sjm_strategy == SJ_OPT_MATERIALIZE_SCAN)
3449 pos->sjm_scan_need_tables=
3450 emb_sj_nest->sj_inner_tables |
3452 pos->sjm_scan_last_inner= idx;
3454 add_alnum(
"choice",
"deferred");
3456 else if (sjm_strategy == SJ_OPT_MATERIALIZE_LOOKUP)
3459 double cost, rowcount;
3460 semijoin_mat_lookup_access_paths(idx, emb_sj_nest, &rowcount, &cost);
3463 trace_one_strategy.add_alnum(
"strategy",
"MaterializeLookup").
3464 add(
"cost", cost).add(
"rows", rowcount).
3466 if (cost < *current_cost || pos->dups_producing_tables)
3474 sj_strategy= SJ_OPT_MATERIALIZE_LOOKUP;
3475 *current_cost= cost;
3476 *current_rowcount= rowcount;
3479 trace_one_strategy.add(
"chosen", sj_strategy == SJ_OPT_MATERIALIZE_LOOKUP);
3487 if (pos->sjm_scan_need_tables &&
3488 emb_sj_nest != NULL &&
3490 join->positions[pos->sjm_scan_last_inner].table->emb_sj_nest)
3491 pos->sjm_scan_need_tables= 0;
3493 if (pos->sjm_scan_need_tables &&
3494 !(pos->sjm_scan_need_tables & remaining_tables))
3497 join->positions[pos->sjm_scan_last_inner].table->emb_sj_nest;
3499 double cost, rowcount;
3502 trace_one_strategy.add_alnum(
"strategy",
"MaterializeScan");
3504 semijoin_mat_scan_access_paths(pos->sjm_scan_last_inner, idx,
3505 remaining_tables, sjm_nest,
false,
3507 trace_one_strategy.add(
"cost", cost).
3508 add(
"rows", rowcount).
3518 if (cost < *current_cost || pos->dups_producing_tables)
3520 sj_strategy= SJ_OPT_MATERIALIZE_SCAN;
3521 *current_cost= cost;
3522 *current_rowcount= rowcount;
3525 trace_one_strategy.add(
"chosen", sj_strategy == SJ_OPT_MATERIALIZE_SCAN);
3536 if (!pos->dupsweedout_tables)
3537 pos->first_dupsweedout_table= idx;
3539 pos->dupsweedout_tables|= emb_sj_nest->sj_inner_tables |
3543 if (pos->dupsweedout_tables &&
3544 !(remaining_tables & pos->dupsweedout_tables))
3547 trace_one_strategy.add_alnum(
"strategy",
"DuplicatesWeedout");
3562 double rowcount, cost;
3563 semijoin_dupsweedout_access_paths(pos->first_dupsweedout_table, idx,
3564 remaining_tables, &rowcount, &cost);
3575 add(
"rows", rowcount).
3577 if (cost < *current_cost || pos->dups_producing_tables)
3579 sj_strategy= SJ_OPT_DUPS_WEEDOUT;
3580 *current_cost= cost;
3581 *current_rowcount= rowcount;
3588 trace_one_strategy.add(
"chosen", sj_strategy == SJ_OPT_DUPS_WEEDOUT);
3591 pos->sj_strategy= sj_strategy;
3607 if (sj_strategy != SJ_OPT_NONE)
3608 pos->set_prefix_costs(*current_cost, *current_rowcount);
3667 void Optimize_table_order::backout_nj_state(
const table_map remaining_tables,
3670 DBUG_ASSERT(remaining_tables & tab->table->map);
3673 TABLE_LIST *last_emb= tab->table->pos_in_table_list->embedding;
3675 for (; last_emb != emb_sjm_nest; last_emb= last_emb->embedding)
3678 if (!last_emb->join_cond())
3685 cur_embedding_map|= nest->
nj_map;
3689 cur_embedding_map&= ~nest->
nj_map;
3691 if (!was_fully_covered)
3700 static void trace_plan_prefix(
JOIN *join, uint idx,
3701 table_map excluded_tables)
3703 #ifdef OPTIMIZER_TRACE
3704 THD *
const thd= join->thd;
3706 for (uint i= 0; i < idx; i++)
3708 const TABLE *
const table= join->positions[
i].table->table;
3709 if (!(table->map & excluded_tables))
3711 TABLE_LIST *
const tl= table->pos_in_table_list;
3715 tl->
print(thd, &str, enum_query_type(QT_TO_SYSTEM_CHARSET |
3716 QT_SHOW_SELECT_NUMBER |
3718 QT_DERIVED_TABLE_ONLY_ALIAS));
3719 plan_prefix.add_utf8(str.ptr(), str.length());