45
42
#include "drizzled/join_cache.h"
46
43
#include "drizzled/show.h"
47
44
#include "drizzled/field/blob.h"
48
#include "drizzled/optimizer/position.h"
49
#include "drizzled/optimizer/sargable_param.h"
50
#include "drizzled/optimizer/key_use.h"
51
#include "drizzled/optimizer/range.h"
52
#include "drizzled/optimizer/sum.h"
53
#include "drizzled/optimizer/explain_plan.h"
54
#include "drizzled/records.h"
55
#include "drizzled/probes.h"
56
#include "drizzled/internal/my_bit.h"
57
#include "drizzled/internal/my_sys.h"
58
#include "drizzled/internal/iocache.h"
45
#include "mysys/my_bit.h"
60
47
#include <algorithm>
62
49
using namespace std;
67
extern plugin::StorageEngine *heap_engine;
68
extern std::bitset<12> test_flags;
70
51
/** Declarations of static functions used in this source file. */
71
52
static bool make_group_fields(JOIN *main_join, JOIN *curr_join);
72
53
static void calc_group_buffer(JOIN *join,order_st *group);
73
54
static bool alloc_group_fields(JOIN *join,order_st *group);
56
TODO: 'find_best' is here only temporarily until 'greedy_search' is
59
static bool find_best(JOIN *join,table_map rest_tables,uint32_t index, double record_count,double read_time);
74
60
static uint32_t cache_record_length(JOIN *join, uint32_t index);
75
61
static double prev_record_reads(JOIN *join, uint32_t idx, table_map found_ref);
76
62
static bool get_best_combination(JOIN *join);
77
static void set_position(JOIN *join,
80
optimizer::KeyUse *key);
63
static void set_position(JOIN *join,uint32_t index,JoinTable *table,KeyUse *key);
81
64
static bool choose_plan(JOIN *join,table_map join_tables);
82
65
static void best_access_path(JOIN *join, JoinTable *s,
97
80
static uint32_t determine_search_depth(JOIN* join);
98
81
static bool make_simple_join(JOIN *join,Table *tmp_table);
99
82
static void make_outerjoin_info(JOIN *join);
100
static bool make_join_select(JOIN *join, optimizer::SqlSelect *select,COND *item);
83
static bool make_join_select(JOIN *join,SQL_SELECT *select,COND *item);
101
84
static bool make_join_readinfo(JOIN *join, uint64_t options, uint32_t no_jbuf_after);
102
85
static void update_depend_map(JOIN *join);
103
86
static void update_depend_map(JOIN *join, order_st *order);
249
233
(Subquery is non-correlated ||
250
234
Subquery is correlated to any query outer to IN predicate ||
251
235
(Subquery is correlated to the immediate outer query &&
252
Subquery !contains {GROUP BY, ORDER BY [LIMIT],
236
Subquery !contains {GROUP BY, order_st BY [LIMIT],
253
237
aggregate functions) && subquery predicate is not under "NOT IN"))
254
238
6. No execution method was already chosen (by a prepared statement).
322
goto err; /* purecov: inspected */
341
* The below will create the new table for
342
* CREATE TABLE ... SELECT
344
* @see create_table_from_items() in drizzled/sql_insert.cc
346
324
if (result && result->prepare(fields_list, unit_arg))
325
goto err; /* purecov: inspected */
349
327
/* Init join struct */
350
328
count_field_types(select_lex, &tmp_table_param, all_fields, 0);
507
optimizer::sum_query() returns HA_ERR_KEY_NOT_FOUND if no rows match
485
opt_sum_query() returns HA_ERR_KEY_NOT_FOUND if no rows match
508
486
to the WHERE conditions,
509
487
or 1 if all items were resolved,
510
488
or 0, or an error number HA_ERR_...
512
if ((res= optimizer::sum_query(select_lex->leaf_tables, all_fields, conds)))
490
if ((res=opt_sum_query(select_lex->leaf_tables, all_fields, conds)))
514
492
if (res == HA_ERR_KEY_NOT_FOUND)
532
510
tables_list= 0; // All tables resolved
534
512
Extract all table-independent conditions and replace the WHERE
535
clause with them. All other conditions were computed by optimizer::sum_query
513
clause with them. All other conditions were computed by opt_sum_query
536
514
and the MIN/MAX/COUNT function(s) have been replaced by constants,
537
515
so there is no need to compute the whole WHERE clause again.
538
516
Notice that make_cond_for_table() will always succeed to remove all
539
computed conditions, because optimizer::sum_query() is applicable only to
517
computed conditions, because opt_sum_query() is applicable only to
541
519
Preserve conditions for EXPLAIN.
595
573
/* Handle the case where we have an OUTER JOIN without a WHERE */
596
574
conds=new Item_int((int64_t) 1,1); // Always true
598
select= optimizer::make_select(*table, const_table_map,
599
const_table_map, conds, 1, &error);
576
select= make_select(*table, const_table_map,
577
const_table_map, conds, 1, &error);
579
{ /* purecov: inspected */
580
error= -1; /* purecov: inspected */
679
656
The FROM clause must contain a single non-constant table.
681
658
if (tables - const_tables == 1 && (group_list || select_distinct) &&
682
! tmp_table_param.sum_func_count &&
683
(! join_tab[const_tables].select ||
684
! join_tab[const_tables].select->quick ||
659
!tmp_table_param.sum_func_count &&
660
(!join_tab[const_tables].select ||
661
!join_tab[const_tables].select->quick ||
685
662
join_tab[const_tables].select->quick->get_type() !=
686
optimizer::QuickSelectInterface::QS_TYPE_GROUP_MIN_MAX))
663
QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX))
688
665
if (group_list && list_contains_unique_index(join_tab[const_tables].table, find_field_in_order_list, (void *) group_list))
691
668
We have found that grouping can be removed since groups correspond to
692
669
only one row anyway, but we still have to guarantee correct result
693
670
order. The line below effectively rewrites the query from GROUP BY
694
<fields> to ORDER BY <fields>. There are two exceptions:
671
<fields> to order_st BY <fields>. There are two exceptions:
695
672
- if skip_sort_order is set (see above), then we can simply skip
697
- we can only rewrite ORDER BY if the ORDER BY fields are 'compatible'
674
- we can only rewrite order_st BY if the order_st BY fields are 'compatible'
698
675
with the GROUP BY ones, i.e. either one is a prefix of another.
699
We only check if the ORDER BY is a prefix of GROUP BY. In this case
676
We only check if the order_st BY is a prefix of GROUP BY. In this case
700
677
test_if_subpart() copies the ASC/DESC attributes from the original
702
679
If GROUP BY is a prefix of order_st BY, then it is safe to leave
705
if (! order || test_if_subpart(group_list, order))
682
if (!order || test_if_subpart(group_list, order))
706
683
order= skip_sort_order ? 0 : group_list;
708
685
If we have an IGNORE INDEX FOR GROUP BY(fields) clause, this must be
826
803
This has to be done if all tables are not already read (const tables)
827
804
and one of the following conditions holds:
828
805
- We are using DISTINCT (simple distinct's are already optimized away)
829
- We are using an ORDER BY or GROUP BY on fields not in the first table
830
- We are using different ORDER BY and GROUP BY orders
806
- We are using an order_st BY or GROUP BY on fields not in the first table
807
- We are using different order_st BY and GROUP BY orders
831
808
- The user wants us to buffer the result.
833
810
need_tmp= (const_tables != tables &&
1134
1108
if (exec_tmp_table1)
1136
exec_tmp_table1->cursor->extra(HA_EXTRA_RESET_STATE);
1137
exec_tmp_table1->cursor->ha_delete_all_rows();
1110
exec_tmp_table1->file->extra(HA_EXTRA_RESET_STATE);
1111
exec_tmp_table1->file->ha_delete_all_rows();
1138
1112
exec_tmp_table1->free_io_cache();
1139
1113
exec_tmp_table1->filesort_free_buffers();
1141
1115
if (exec_tmp_table2)
1143
exec_tmp_table2->cursor->extra(HA_EXTRA_RESET_STATE);
1144
exec_tmp_table2->cursor->ha_delete_all_rows();
1117
exec_tmp_table2->file->extra(HA_EXTRA_RESET_STATE);
1118
exec_tmp_table2->file->ha_delete_all_rows();
1145
1119
exec_tmp_table2->free_io_cache();
1146
1120
exec_tmp_table2->filesort_free_buffers();
1219
1193
/* Only test of functions */
1220
1194
if (select_options & SELECT_DESCRIBE)
1222
optimizer::ExplainPlan planner(this,
1226
(zero_result_cause ? zero_result_cause : "No tables used"));
1227
planner.printPlan();
1195
select_describe(this, false, false, false, (zero_result_cause?zero_result_cause:"No tables used"));
1231
1198
result->send_fields(*columns_list);
2360
2325
item->save_in_result_field(1);
2362
2327
copy_sum_funcs(sum_funcs_end[i+1], sum_funcs_end[i]);
2363
if ((write_error= table_arg->cursor->ha_write_row(table_arg->record[0])))
2328
if ((write_error= table_arg->file->ha_write_row(table_arg->record[0])))
2365
2330
if (create_myisam_from_heap(session, table_arg,
2366
2331
tmp_table_param.start_recinfo,
2416
Cache constant expressions in WHERE, HAVING, ON conditions.
2419
void JOIN::cache_const_exprs()
2421
bool cache_flag= false;
2422
bool *analyzer_arg= &cache_flag;
2424
/* No need in cache if all tables are constant. */
2425
if (const_tables == tables)
2429
conds->compile(&Item::cache_const_expr_analyzer, (unsigned char **)&analyzer_arg,
2430
&Item::cache_const_expr_transformer, (unsigned char *)&cache_flag);
2433
having->compile(&Item::cache_const_expr_analyzer, (unsigned char **)&analyzer_arg,
2434
&Item::cache_const_expr_transformer, (unsigned char *)&cache_flag);
2436
for (JoinTable *tab= join_tab + const_tables; tab < join_tab + tables ; tab++)
2438
if (*tab->on_expr_ref)
2441
(*tab->on_expr_ref)->compile(&Item::cache_const_expr_analyzer,
2442
(unsigned char **)&analyzer_arg,
2443
&Item::cache_const_expr_transformer,
2444
(unsigned char *)&cache_flag);
2452
2383
Process one record of the nested loop join.
2675
2606
if (join->session->killed)
2677
2608
join->session->send_kill_message();
2678
return NESTED_LOOP_KILLED;
2609
return NESTED_LOOP_KILLED; // Aborted by user /* purecov: inspected */
2680
optimizer::SqlSelect *select= join_tab->select;
2611
SQL_SELECT *select=join_tab->select;
2681
2612
if (rc == NESTED_LOOP_OK &&
2682
2613
(!join_tab->cache.select || !join_tab->cache.select->skip_record()))
2819
2750
join->found_records++;
2820
if ((error=table->cursor->ha_write_row(table->record[0])))
2751
if ((error=table->file->ha_write_row(table->record[0])))
2822
if (!table->cursor->is_fatal_error(error, HA_CHECK_DUP))
2753
if (!table->file->is_fatal_error(error, HA_CHECK_DUP))
2824
2755
if (create_myisam_from_heap(join->session, table,
2825
2756
join->tmp_table_param.start_recinfo,
2868
2799
if (item->maybe_null)
2869
2800
group->buff[-1]= (char) group->field->is_null();
2871
if (!table->cursor->index_read_map(table->record[1],
2802
if (!table->file->index_read_map(table->record[1],
2872
2803
join->tmp_table_param.group_buff,
2874
2805
HA_READ_KEY_EXACT))
2875
2806
{ /* Update old record */
2876
2807
table->restoreRecord();
2877
2808
update_tmptable_sum_func(join->sum_funcs,table);
2878
if ((error= table->cursor->ha_update_row(table->record[1],
2809
if ((error= table->file->ha_update_row(table->record[1],
2879
2810
table->record[0])))
2881
table->print_error(error,MYF(0));
2882
return NESTED_LOOP_ERROR;
2812
table->file->print_error(error,MYF(0)); /* purecov: inspected */
2813
return NESTED_LOOP_ERROR; /* purecov: inspected */
2884
2815
return NESTED_LOOP_OK;
2900
2831
init_tmptable_sum_functions(join->sum_funcs);
2901
2832
copy_funcs(join->tmp_table_param.items_to_copy);
2902
if ((error=table->cursor->ha_write_row(table->record[0])))
2833
if ((error=table->file->ha_write_row(table->record[0])))
2904
2835
if (create_myisam_from_heap(join->session, table,
2905
2836
join->tmp_table_param.start_recinfo,
2925
2856
if (join->session->killed) // Aborted by user
2927
2858
join->session->send_kill_message();
2928
return NESTED_LOOP_KILLED;
2859
return NESTED_LOOP_KILLED; /* purecov: inspected */
2931
2862
init_tmptable_sum_functions(join->sum_funcs);
2932
2863
copy_fields(&join->tmp_table_param); // Groups are copied twice.
2933
2864
copy_funcs(join->tmp_table_param.items_to_copy);
2935
if (!(error= table->cursor->ha_write_row(table->record[0])))
2866
if (!(error= table->file->ha_write_row(table->record[0])))
2936
2867
join->send_records++; // New group
2939
if ((int) table->get_dup_key(error) < 0)
2870
if ((int) table->file->get_dup_key(error) < 0)
2941
table->print_error(error,MYF(0));
2942
return NESTED_LOOP_ERROR;
2872
table->file->print_error(error,MYF(0)); /* purecov: inspected */
2873
return NESTED_LOOP_ERROR; /* purecov: inspected */
2944
if (table->cursor->rnd_pos(table->record[1],table->cursor->dup_ref))
2875
if (table->file->rnd_pos(table->record[1],table->file->dup_ref))
2946
table->print_error(error,MYF(0));
2947
return NESTED_LOOP_ERROR;
2877
table->file->print_error(error,MYF(0)); /* purecov: inspected */
2878
return NESTED_LOOP_ERROR; /* purecov: inspected */
2949
2880
table->restoreRecord();
2950
2881
update_tmptable_sum_func(join->sum_funcs,table);
2951
if ((error= table->cursor->ha_update_row(table->record[1],
2882
if ((error= table->file->ha_update_row(table->record[1],
2952
2883
table->record[0])))
2954
table->print_error(error,MYF(0));
2955
return NESTED_LOOP_ERROR;
2885
table->file->print_error(error,MYF(0)); /* purecov: inspected */
2886
return NESTED_LOOP_ERROR; /* purecov: inspected */
2958
2889
return NESTED_LOOP_OK;
3019
- TODO: this function is here only temporarily until 'greedy_search' is
3020
tested and accepted.
3026
static bool find_best(JOIN *join,table_map rest_tables,uint32_t idx,double record_count, double read_time)
3028
Session *session= join->session;
3029
Position partial_pos;
3030
if (session->killed)
3037
read_time+= record_count/(double) TIME_FOR_COMPARE;
3038
partial_pos= join->getPosFromPartialPlan(join->const_tables);
3039
if (join->sort_by_table &&
3040
join->sort_by_table !=
3041
partial_pos.table->table)
3043
read_time+= record_count; // We have to make a temp table
3045
if (read_time < join->best_read)
3047
join->copyPartialPlanIntoOptimalPlan(idx);
3048
join->best_read= read_time - 0.001;
3052
if (read_time+record_count/(double) TIME_FOR_COMPARE >= join->best_read)
3054
return false; /* Found better before */
3058
double best_record_count= DBL_MAX;
3059
double best_read_time= DBL_MAX;
3060
for (JoinTable **pos= join->best_ref+idx ; (s= *pos) ; pos++)
3062
table_map real_table_bit= s->table->map;
3065
partial_pos= join->getPosFromPartialPlan(idx - 1);
3067
if ((rest_tables & real_table_bit) && !(rest_tables & s->dependent) &&
3068
(! idx || ! check_interleaving_with_nj(partial_pos.table, s)))
3070
double records, best;
3071
best_access_path(join, s, session, rest_tables, idx, record_count,
3073
partial_pos= join->getPosFromPartialPlan(idx);
3074
records= partial_pos.records_read;
3075
best= partial_pos.read_time;
3077
Go to the next level only if there hasn't been a better key on
3078
this level! This will cut down the search for a lot simple cases!
3080
double current_record_count= record_count * records;
3081
double current_read_time= read_time + best;
3082
if (best_record_count > current_record_count ||
3083
best_read_time > current_read_time ||
3084
(idx == join->const_tables && s->table == join->sort_by_table))
3086
if (best_record_count >= current_record_count &&
3087
best_read_time >= current_read_time &&
3088
(! (s->key_dependent & rest_tables) ||
3089
partial_pos.isConstTable()))
3091
best_record_count= current_record_count;
3092
best_read_time= current_read_time;
3094
std::swap(join->best_ref[idx], *pos);
3095
if (find_best(join,rest_tables & ~real_table_bit,idx+1,
3096
current_record_count,current_read_time))
3100
std::swap(join->best_ref[idx], *pos);
3102
restore_prev_nj_state(s);
3103
if (join->select_options & SELECT_STRAIGHT_JOIN)
3104
break; // Don't test all combinations
3086
3110
static uint32_t cache_record_length(JOIN *join,uint32_t idx)
3088
3112
uint32_t length=0;
3154
3178
static double prev_record_reads(JOIN *join, uint32_t idx, table_map found_ref)
3156
3180
double found=1.0;
3157
optimizer::Position *pos_end= join->getSpecificPosInPartialPlan(-1);
3158
for (optimizer::Position *pos= join->getSpecificPosInPartialPlan(idx - 1);
3181
Position *pos_end= join->getSpecificPosInPartialPlan(-1);
3182
for (Position *pos= join->getSpecificPosInPartialPlan(idx - 1);
3159
3183
pos != pos_end;
3162
if (pos->examinePosition(found_ref))
3186
if (pos->table->table->map & found_ref)
3164
found_ref|= pos->getRefDependMap();
3188
found_ref|= pos->ref_depend_map;
3166
3190
For the case of "t1 LEFT JOIN t2 ON ..." where t2 is a const table
3167
3191
with no matching row we will get position[t2].records_read==0.
3243
3267
/** Save const tables first as used tables. */
3244
static void set_position(JOIN *join,
3247
optimizer::KeyUse *key)
3268
static void set_position(JOIN *join,uint32_t idx,JoinTable *table,KeyUse *key)
3249
optimizer::Position tmp_pos(1.0, /* This is a const table */
3271
tmp_pos.table= table;
3273
tmp_pos.records_read= 1.0; /* This is a const table */
3274
tmp_pos.ref_depend_map= 0;
3254
3275
join->setPosInPartialPlan(idx, tmp_pos);
3256
3277
/* Move the const table as down as possible in best_ref */
3299
3324
Apply heuristic: pre-sort all access plans with respect to the number of
3300
3325
records accessed.
3302
internal::my_qsort(join->best_ref + join->const_tables,
3303
join->tables - join->const_tables, sizeof(JoinTable*),
3304
straight_join ? join_tab_cmp_straight : join_tab_cmp);
3327
my_qsort(join->best_ref + join->const_tables,
3328
join->tables - join->const_tables, sizeof(JoinTable*),
3329
straight_join ? join_tab_cmp_straight : join_tab_cmp);
3305
3330
if (straight_join)
3307
3332
optimize_straight_join(join, join_tables);
3311
if (search_depth == 0)
3312
/* Automatically determine a reasonable value for 'search_depth' */
3313
search_depth= determine_search_depth(join);
3314
if (greedy_search(join, join_tables, search_depth, prune_level))
3336
if (search_depth == MAX_TABLES+2)
3338
TODO: 'MAX_TABLES+2' denotes the old implementation of find_best before
3339
the greedy version. Will be removed when greedy_search is approved.
3341
join->best_read= DBL_MAX;
3342
if (find_best(join, join_tables, join->const_tables, 1.0, 0.0))
3347
if (search_depth == 0)
3348
/* Automatically determine a reasonable value for 'search_depth' */
3349
search_depth= determine_search_depth(join);
3350
if (greedy_search(join, join_tables, search_depth, prune_level))
3372
3409
{ /* Use key if possible */
3373
3410
Table *table= s->table;
3374
optimizer::KeyUse *keyuse= NULL;
3375
optimizer::KeyUse *start_key= NULL;
3411
KeyUse *keyuse,*start_key=0;
3376
3412
double best_records= DBL_MAX;
3377
3413
uint32_t max_key_part=0;
3379
3415
/* Test how we can use keys */
3380
3416
rec= s->records/MATCHING_ROWS_IN_OTHER_TABLE; // Assumed records/key
3381
for (keyuse= s->keyuse; keyuse->getTable() == table; )
3417
for (keyuse=s->keyuse ; keyuse->table == table ;)
3383
3419
key_part_map found_part= 0;
3384
3420
table_map found_ref= 0;
3385
uint32_t key= keyuse->getKey();
3386
KEY *keyinfo= table->key_info + key;
3421
uint32_t key= keyuse->key;
3422
KEY *keyinfo= table->key_info+key;
3387
3423
/* Bitmap of keyparts where the ref access is over 'keypart=const': */
3388
3424
key_part_map const_part= 0;
3389
3425
/* The or-null keypart in ref-or-null access: */
3405
3441
if 1. expression doesn't refer to forward tables
3406
3442
2. we won't get two ref-or-null's
3408
if (! (remaining_tables & keyuse->getUsedTables()) &&
3409
! (ref_or_null_part && (keyuse->getOptimizeFlags() &
3410
KEY_OPTIMIZE_REF_OR_NULL)))
3444
if (!(remaining_tables & keyuse->used_tables) &&
3445
!(ref_or_null_part && (keyuse->optimize &
3446
KEY_OPTIMIZE_REF_OR_NULL)))
3412
found_part|= keyuse->getKeypartMap();
3413
if (! (keyuse->getUsedTables() & ~join->const_table_map))
3414
const_part|= keyuse->getKeypartMap();
3448
found_part|= keyuse->keypart_map;
3449
if (!(keyuse->used_tables & ~join->const_table_map))
3450
const_part|= keyuse->keypart_map;
3416
3452
double tmp2= prev_record_reads(join, idx, (found_ref |
3417
keyuse->getUsedTables()));
3453
keyuse->used_tables));
3418
3454
if (tmp2 < best_prev_record_reads)
3420
best_part_found_ref= keyuse->getUsedTables() & ~join->const_table_map;
3456
best_part_found_ref= keyuse->used_tables & ~join->const_table_map;
3421
3457
best_prev_record_reads= tmp2;
3423
if (rec > keyuse->getTableRows())
3424
rec= keyuse->getTableRows();
3459
if (rec > keyuse->ref_table_rows)
3460
rec= keyuse->ref_table_rows;
3426
3462
If there is one 'key_column IS NULL' expression, we can
3427
3463
use this ref_or_null optimisation of this field
3429
if (keyuse->getOptimizeFlags() & KEY_OPTIMIZE_REF_OR_NULL)
3430
ref_or_null_part|= keyuse->getKeypartMap();
3465
if (keyuse->optimize & KEY_OPTIMIZE_REF_OR_NULL)
3466
ref_or_null_part |= keyuse->keypart_map;
3434
} while (keyuse->getTable() == table && keyuse->getKey() == key &&
3435
keyuse->getKeypart() == keypart);
3436
found_ref|= best_part_found_ref;
3437
} while (keyuse->getTable() == table && keyuse->getKey() == key);
3470
} while (keyuse->table == table && keyuse->key == key &&
3471
keyuse->keypart == keypart);
3472
found_ref|= best_part_found_ref;
3473
} while (keyuse->table == table && keyuse->key == key);
3440
3476
Assume that that each key matches a proportional part of table.
3539
3575
Set tmp to (previous record count) * (records / combination)
3541
3577
if ((found_part & 1) &&
3542
(!(table->index_flags(key) & HA_ONLY_WHOLE_INDEX) ||
3543
found_part == PREV_BITS(uint, keyinfo->key_parts)))
3578
(!(table->file->index_flags(key, 0, 0) & HA_ONLY_WHOLE_INDEX) ||
3579
found_part == PREV_BITS(uint,keyinfo->key_parts)))
3545
3581
max_key_part= max_part_bit(found_part);
3744
3780
if ((records >= s->found_records || best > s->read_time) && // (1)
3745
! (s->quick && best_key && s->quick->index == best_key->getKey() && // (2)
3746
best_max_key_part >= s->table->quick_key_parts[best_key->getKey()]) &&// (2)
3747
! ((s->table->cursor->getEngine()->check_flag(HTON_BIT_TABLE_SCAN_ON_INDEX)) && // (3)
3748
! s->table->covering_keys.none() && best_key && !s->quick) && // (3)
3749
! (s->table->force_index && best_key && !s->quick)) // (4)
3781
!(s->quick && best_key && s->quick->index == best_key->key && // (2)
3782
best_max_key_part >= s->table->quick_key_parts[best_key->key]) &&// (2)
3783
!((s->table->file->ha_table_flags() & HA_TABLE_SCAN_ON_INDEX) && // (3)
3784
! s->table->covering_keys.none() && best_key && !s->quick) &&// (3)
3785
!(s->table->force_index && best_key && !s->quick)) // (4)
3750
3786
{ // Check full join
3751
3787
ha_rows rnd_records= s->found_records;
3895
3932
record_count, read_time);
3896
3933
/* compute the cost of the new plan extended with 's' */
3897
3934
partial_pos= join->getPosFromPartialPlan(idx);
3898
record_count*= partial_pos.getFanout();
3899
read_time+= partial_pos.getCost();
3935
record_count*= partial_pos.records_read;
3936
read_time+= partial_pos.read_time;
3900
3937
join_tables&= ~(s->table->map);
3904
3941
read_time+= record_count / (double) TIME_FOR_COMPARE;
3905
3942
partial_pos= join->getPosFromPartialPlan(join->const_tables);
3906
3943
if (join->sort_by_table &&
3907
partial_pos.hasTableForSorting(join->sort_by_table))
3944
join->sort_by_table != partial_pos.table->table)
3908
3945
read_time+= record_count; // We have to make a temp table
3909
3946
join->copyPartialPlanIntoOptimalPlan(idx);
3910
3947
join->best_read= read_time;
4000
4037
uint32_t idx= join->const_tables; // index into 'join->best_ref'
4001
4038
uint32_t best_idx;
4002
4039
uint32_t size_remain; // cardinality of remaining_tables
4003
optimizer::Position best_pos;
4004
4041
JoinTable *best_table; // the next plan node to be added to the curr QEP
4006
4043
/* number of tables that remain to be optimized */
4007
size_remain= internal::my_count_bits(remaining_tables);
4044
size_remain= my_count_bits(remaining_tables);
4010
4047
/* Find the extension of the current QEP with the lowest cost */
4042
4079
std::swap(join->best_ref[idx], join->best_ref[best_idx]);
4044
4081
/* compute the cost of the new plan extended with 'best_table' */
4045
optimizer::Position partial_pos= join->getPosFromPartialPlan(idx);
4046
record_count*= partial_pos.getFanout();
4047
read_time+= partial_pos.getCost();
4082
Position partial_pos= join->getPosFromPartialPlan(idx);
4083
record_count*= partial_pos.records_read;
4084
read_time+= partial_pos.read_time;
4049
4086
remaining_tables&= ~(best_table->table->map);
4198
4235
partial_pos= join->getPosFromPartialPlan(idx - 1);
4200
4237
if ((remaining_tables & real_table_bit) &&
4201
! (remaining_tables & s->dependent) &&
4202
(! idx || ! check_interleaving_with_nj(partial_pos.getJoinTable(), s)))
4238
!(remaining_tables & s->dependent) &&
4239
(!idx || !check_interleaving_with_nj(partial_pos.table, s)))
4204
4241
double current_record_count, current_read_time;
4215
4252
record_count, read_time);
4216
4253
/* Compute the cost of extending the plan with 's' */
4217
4254
partial_pos= join->getPosFromPartialPlan(idx);
4218
current_record_count= record_count * partial_pos.getFanout();
4219
current_read_time= read_time + partial_pos.getCost();
4255
current_record_count= record_count * partial_pos.records_read;
4256
current_read_time= read_time + partial_pos.read_time;
4221
4258
/* Expand only partial plans with lower cost than the best QEP so far */
4222
4259
if ((current_read_time +
4274
4311
partial_pos= join->getPosFromPartialPlan(join->const_tables);
4275
4312
current_read_time+= current_record_count / (double) TIME_FOR_COMPARE;
4276
4313
if (join->sort_by_table &&
4277
partial_pos.hasTableForSorting(join->sort_by_table))
4314
join->sort_by_table !=
4315
partial_pos.table->table)
4278
4316
/* We have to make a temp table */
4279
4317
current_read_time+= current_record_count;
4280
4318
if ((search_depth == 1) || (current_read_time < join->best_read))
4497
static bool make_join_select(JOIN *join,
4498
optimizer::SqlSelect *select,
4535
static bool make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
4501
4537
Session *session= join->session;
4502
optimizer::Position cur_pos;
4505
4541
add_not_null_conds(join);
4681
4717
cur_pos= join->getPosFromOptimalPlan(i);
4682
4718
if ((cond && (! ((tab->keys & tab->const_keys) == tab->keys) && i > 0)) ||
4683
4719
(! tab->const_keys.none() && (i == join->const_tables) &&
4684
(join->unit->select_limit_cnt < cur_pos.getFanout()) && ((join->select_options & OPTION_FOUND_ROWS) == false)))
4720
(join->unit->select_limit_cnt < cur_pos.records_read) && ((join->select_options & OPTION_FOUND_ROWS) == false)))
4686
4722
/* Join with outer join condition */
4687
4723
COND *orig_cond= sel->cond;
5536
5567
reclength= entry->s->reclength-offset;
5538
5569
entry->free_io_cache(); // Safety
5539
entry->cursor->info(HA_STATUS_VARIABLE);
5570
entry->file->info(HA_STATUS_VARIABLE);
5540
5571
if (entry->s->db_type() == heap_engine ||
5541
5572
(!entry->s->blob_fields &&
5542
((ALIGN_SIZE(reclength) + HASH_OVERHEAD) * entry->cursor->stats.records <
5573
((ALIGN_SIZE(reclength) + HASH_OVERHEAD) * entry->file->stats.records <
5543
5574
session->variables.sortbuff_size)))
5544
5575
error= remove_dup_with_hash_index(join->session, entry,
5545
5576
field_count, first_field,
5598
uint32_t table_count;
5599
uint32_t const_count;
5601
table_map found_const_table_map;
5602
table_map all_table_map;
5603
table_map found_ref;
5607
Table **table_vector= NULL;
5608
JoinTable *stat= NULL;
5609
JoinTable *stat_end= NULL;
5611
JoinTable **stat_ref= NULL;
5612
optimizer::KeyUse *keyuse= NULL;
5613
optimizer::KeyUse *start_keyuse= NULL;
5614
table_map outer_join= 0;
5615
vector<optimizer::SargableParam> sargables;
5628
uint32_t i,table_count,const_count,key;
5629
table_map found_const_table_map, all_table_map, found_ref, refs;
5630
key_map const_ref, eq_part;
5631
Table **table_vector;
5632
JoinTable *stat,*stat_end,*s,**stat_ref;
5633
KeyUse *keyuse,*start_keyuse;
5634
table_map outer_join=0;
5635
SARGABLE_PARAM *sargables= 0;
5616
5636
JoinTable *stat_vector[MAX_TABLES+1];
5617
optimizer::Position *partial_pos;
5637
Position *partial_pos;
5619
table_count= join->tables;
5620
stat= (JoinTable*) join->session->calloc(sizeof(JoinTable)*table_count);
5621
stat_ref= (JoinTable**) join->session->alloc(sizeof(JoinTable*)*MAX_TABLES);
5622
table_vector= (Table**) join->session->alloc(sizeof(Table*)*(table_count*2));
5639
table_count=join->tables;
5640
stat=(JoinTable*) join->session->calloc(sizeof(JoinTable)*table_count);
5641
stat_ref=(JoinTable**) join->session->alloc(sizeof(JoinTable*)*MAX_TABLES);
5642
table_vector=(Table**) join->session->alloc(sizeof(Table*)*(table_count*2));
5623
5643
if (! stat || ! stat_ref || ! table_vector)
5644
return 1; // Eom /* purecov: inspected */
5626
5646
join->best_ref=stat_vector;
5641
5661
s->needed_reg.reset();
5642
5662
table_vector[i]=s->table=table=tables->table;
5643
5663
table->pos_in_table_list= tables;
5644
error= table->cursor->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
5664
error= table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
5647
table->print_error(error, MYF(0));
5667
table->file->print_error(error, MYF(0));
5650
5670
table->quick_keys.reset();
5659
5679
s->dependent= tables->dep_tables;
5660
5680
s->key_dependent= 0;
5661
table->quick_condition_rows= table->cursor->stats.records;
5681
if (tables->schema_table)
5682
table->file->stats.records= 2;
5683
table->quick_condition_rows= table->file->stats.records;
5663
5685
s->on_expr_ref= &tables->on_expr;
5664
5686
if (*s->on_expr_ref)
5666
5688
/* s is the only inner table of an outer join */
5667
if (!table->cursor->stats.records && !embedding)
5689
if (!table->file->stats.records && !embedding)
5668
5690
{ // Empty table
5669
5691
s->dependent= 0; // Ignore LEFT JOIN depend.
5670
set_position(join, const_count++, s, (optimizer::KeyUse*) 0);
5692
set_position(join,const_count++,s,(KeyUse*) 0);
5673
5695
outer_join|= table->map;
5691
5713
while (embedding);
5694
if ((table->cursor->stats.records <= 1) && !s->dependent &&
5695
(table->cursor->getEngine()->check_flag(HTON_BIT_STATS_RECORDS_IS_EXACT)) &&
5716
if ((table->file->stats.records <= 1) && !s->dependent &&
5717
(table->file->ha_table_flags() & HA_STATS_RECORDS_IS_EXACT) &&
5696
5718
!join->no_const_tables)
5698
set_position(join, const_count++, s, (optimizer::KeyUse*) 0);
5720
set_position(join,const_count++,s,(KeyUse*) 0);
5701
5723
stat_vector[i]=0;
5738
5760
if (conds || outer_join)
5739
5761
if (update_ref_and_keys(join->session, keyuse_array, stat, join->tables,
5740
5762
conds, join->cond_equal,
5741
~outer_join, join->select_lex, sargables))
5763
~outer_join, join->select_lex, &sargables))
5744
5766
/* Read tables with 0 or 1 rows (system tables) */
5745
5767
join->const_table_map= 0;
5747
optimizer::Position *p_pos= join->getFirstPosInPartialPlan();
5748
optimizer::Position *p_end= join->getSpecificPosInPartialPlan(const_count);
5769
Position *p_pos= join->getFirstPosInPartialPlan();
5770
Position *p_end= join->getSpecificPosInPartialPlan(const_count);
5749
5771
while (p_pos < p_end)
5752
s= p_pos->getJoinTable();
5753
5775
s->type= AM_SYSTEM;
5754
5776
join->const_table_map|=s->table->map;
5755
5777
if ((tmp= join_read_const_table(s, p_pos)))
5796
5818
TODO. Apply single row substitution to null complemented inner tables
5797
5819
for nested outer join operations.
5799
while (keyuse->getTable() == table)
5821
while (keyuse->table == table)
5801
if (! (keyuse->getVal()->used_tables() & ~join->const_table_map) &&
5802
keyuse->getVal()->is_null() && keyuse->isNullRejected())
5823
if (!(keyuse->val->used_tables() & ~join->const_table_map) &&
5824
keyuse->val->is_null() && keyuse->null_rejecting)
5804
5826
s->type= AM_CONST;
5805
5827
table->mark_as_null_row();
5806
5828
found_const_table_map|= table->map;
5807
5829
join->const_table_map|= table->map;
5808
set_position(join, const_count++, s, (optimizer::KeyUse*) 0);
5830
set_position(join,const_count++,s,(KeyUse*) 0);
5809
5831
goto more_const_tables_found;
5817
5839
// All dep. must be constants
5818
5840
if (s->dependent & ~(found_const_table_map))
5820
if (table->cursor->stats.records <= 1L &&
5821
(table->cursor->getEngine()->check_flag(HTON_BIT_STATS_RECORDS_IS_EXACT)) &&
5842
if (table->file->stats.records <= 1L &&
5843
(table->file->ha_table_flags() & HA_STATS_RECORDS_IS_EXACT) &&
5822
5844
!table->pos_in_table_list->embedding)
5823
5845
{ // system table
5825
5847
s->type= AM_SYSTEM;
5826
5848
join->const_table_map|=table->map;
5827
set_position(join, const_count++, s, (optimizer::KeyUse*) 0);
5849
set_position(join,const_count++,s,(KeyUse*) 0);
5828
5850
partial_pos= join->getSpecificPosInPartialPlan(const_count - 1);
5829
5851
if ((tmp= join_read_const_table(s, partial_pos)))
5840
5862
if ((keyuse=s->keyuse))
5842
5864
s->type= AM_REF;
5843
while (keyuse->getTable() == table)
5865
while (keyuse->table == table)
5845
start_keyuse= keyuse;
5846
key= keyuse->getKey();
5867
start_keyuse=keyuse;
5847
5869
s->keys.set(key); // QQ: remove this ?
5851
5873
eq_part.reset();
5854
if (keyuse->getVal()->type() != Item::NULL_ITEM &&
5855
! keyuse->getOptimizeFlags())
5876
if (keyuse->val->type() != Item::NULL_ITEM && !keyuse->optimize)
5857
if (! ((~found_const_table_map) & keyuse->getUsedTables()))
5858
const_ref.set(keyuse->getKeypart());
5878
if (!((~found_const_table_map) & keyuse->used_tables))
5879
const_ref.set(keyuse->keypart);
5860
refs|= keyuse->getUsedTables();
5861
eq_part.set(keyuse->getKeypart());
5881
refs|=keyuse->used_tables;
5882
eq_part.set(keyuse->keypart);
5864
} while (keyuse->getTable() == table && keyuse->getKey() == key);
5885
} while (keyuse->table == table && keyuse->key == key);
5866
5887
if (is_keymap_prefix(eq_part, table->key_info[key].key_parts) &&
5867
! table->pos_in_table_list->embedding)
5888
!table->pos_in_table_list->embedding)
5869
5890
if ((table->key_info[key].flags & (HA_NOSAME)) == HA_NOSAME)
5874
5895
ref_changed = 1;
5875
5896
s->type= AM_CONST;
5876
5897
join->const_table_map|= table->map;
5877
set_position(join, const_count++, s, start_keyuse);
5898
set_position(join,const_count++,s,start_keyuse);
5878
5899
if (create_ref_for_key(join, s, start_keyuse, found_const_table_map))
5880
5901
partial_pos= join->getSpecificPosInPartialPlan(const_count - 1);
5902
5923
Update info on indexes that can be used for search lookups as
5903
5924
reading const tables may has added new sargable predicates.
5905
if (const_count && ! sargables.empty())
5926
if (const_count && sargables)
5907
vector<optimizer::SargableParam>::iterator iter= sargables.begin();
5908
while (iter != sargables.end())
5928
for( ; sargables->field ; sargables++)
5910
Field *field= (*iter).getField();
5930
Field *field= sargables->field;
5911
5931
JoinTable *join_tab= field->table->reginfo.join_tab;
5912
5932
key_map possible_keys= field->key_start;
5913
5933
possible_keys&= field->table->keys_in_use_for_query;
5914
bool is_const= true;
5915
for (uint32_t j= 0; j < (*iter).getNumValues(); j++)
5916
is_const&= (*iter).isConstItem(j);
5935
for (uint32_t j=0; j < sargables->num_values; j++)
5936
is_const&= sargables->arg_value[j]->const_item();
5918
5938
join_tab[0].const_keys|= possible_keys;
5954
5973
!s->table->pos_in_table_list->embedding)
5956
5975
ha_rows records;
5957
optimizer::SqlSelect *select= NULL;
5958
select= optimizer::make_select(s->table, found_const_table_map, found_const_table_map, *s->on_expr_ref ? *s->on_expr_ref : conds, 1, &error);
5977
select= make_select(s->table, found_const_table_map, found_const_table_map, *s->on_expr_ref ? *s->on_expr_ref : conds, 1, &error);
5961
5980
records= get_quick_record_count(join->session, select, s->table, &s->const_keys, join->row_limit);
6001
6020
if (join->const_tables != join->tables)
6003
6022
optimize_keyuse(join, keyuse_array);
6004
DRIZZLE_QUERY_OPT_CHOOSE_PLAN_START(join->session->query.c_str(), join->session->thread_id);
6005
bool res= choose_plan(join, all_table_map & ~join->const_table_map);
6006
DRIZZLE_QUERY_OPT_CHOOSE_PLAN_DONE(res ? 1 : 0);
6023
if (choose_plan(join, all_table_map & ~join->const_table_map))
6232
6248
error=(int) cond->add(join_tab->select->cond);
6233
6249
join_tab->select_cond=join_tab->select->cond=cond;
6235
else if ((join_tab->select= optimizer::make_select(join_tab->table, 0, 0, cond, 0,
6251
else if ((join_tab->select= make_select(join_tab->table, 0, 0, cond, 0,
6237
6253
join_tab->select_cond=cond;
6239
6255
return(error ? true : false);