20
mysql_select and join optimization
20
select_query and join optimization
22
22
@defgroup Query_Optimizer Query Optimizer
28
28
#include <iostream>
29
29
#include <algorithm>
32
#include "drizzled/sql_select.h" /* include join.h */
34
#include "drizzled/error.h"
35
#include "drizzled/gettext.h"
36
#include "drizzled/util/test.h"
37
#include "drizzled/name_resolution_context_state.h"
38
#include "drizzled/nested_join.h"
39
#include "drizzled/probes.h"
40
#include "drizzled/show.h"
41
#include "drizzled/item/cache.h"
42
#include "drizzled/item/cmpfunc.h"
43
#include "drizzled/item/copy_string.h"
44
#include "drizzled/item/uint.h"
45
#include "drizzled/cached_item.h"
46
#include "drizzled/sql_base.h"
47
#include "drizzled/field/blob.h"
48
#include "drizzled/check_stack_overrun.h"
49
#include "drizzled/lock.h"
50
#include "drizzled/item/outer_ref.h"
51
#include "drizzled/index_hint.h"
52
#include "drizzled/records.h"
53
#include "drizzled/internal/iocache.h"
54
#include "drizzled/drizzled.h"
56
#include "drizzled/sql_union.h"
57
#include "drizzled/optimizer/key_field.h"
58
#include "drizzled/optimizer/position.h"
59
#include "drizzled/optimizer/sargable_param.h"
60
#include "drizzled/optimizer/key_use.h"
61
#include "drizzled/optimizer/range.h"
62
#include "drizzled/optimizer/quick_range_select.h"
63
#include "drizzled/optimizer/quick_ror_intersect_select.h"
65
#include "drizzled/filesort.h"
32
#include <drizzled/sql_select.h> /* include join.h */
34
#include <drizzled/error.h>
35
#include <drizzled/gettext.h>
36
#include <drizzled/util/test.h>
37
#include <drizzled/name_resolution_context_state.h>
38
#include <drizzled/nested_join.h>
39
#include <drizzled/probes.h>
40
#include <drizzled/show.h>
41
#include <drizzled/item/cache.h>
42
#include <drizzled/item/cmpfunc.h>
43
#include <drizzled/item/copy_string.h>
44
#include <drizzled/item/uint.h>
45
#include <drizzled/cached_item.h>
46
#include <drizzled/sql_base.h>
47
#include <drizzled/field/blob.h>
48
#include <drizzled/check_stack_overrun.h>
49
#include <drizzled/lock.h>
50
#include <drizzled/item/outer_ref.h>
51
#include <drizzled/index_hint.h>
52
#include <drizzled/records.h>
53
#include <drizzled/internal/iocache.h>
54
#include <drizzled/drizzled.h>
55
#include <drizzled/plugin/storage_engine.h>
56
#include <drizzled/sql_union.h>
57
#include <drizzled/optimizer/key_field.h>
58
#include <drizzled/optimizer/position.h>
59
#include <drizzled/optimizer/sargable_param.h>
60
#include <drizzled/optimizer/key_use.h>
61
#include <drizzled/optimizer/range.h>
62
#include <drizzled/optimizer/quick_range_select.h>
63
#include <drizzled/optimizer/quick_ror_intersect_select.h>
64
#include <drizzled/filesort.h>
65
#include <drizzled/sql_lex.h>
66
#include <drizzled/session.h>
67
#include <drizzled/sort_field.h>
68
#include <drizzled/select_result.h>
69
#include <drizzled/key.h>
70
#include <drizzled/my_hash.h>
67
72
using namespace std;
72
76
static int sort_keyuse(optimizer::KeyUse *a, optimizer::KeyUse *b);
73
77
static COND *build_equal_items(Session *session, COND *cond,
131
135
unit->set_limit(unit->global_parameters);
132
136
session->session_marker= 0;
134
'options' of mysql_select will be set in JOIN, as far as JOIN for
138
'options' of select_query will be set in JOIN, as far as JOIN for
135
139
every PS/SP execution new, we will not need reset this flag if
136
140
setup_tables_done_option changed for next rexecution
138
res= mysql_select(session,
142
res= select_query(session,
139
143
&select_lex->ref_pointer_array,
140
144
(TableList*) select_lex->table_list.first,
141
145
select_lex->with_wild,
142
146
select_lex->item_list,
143
147
select_lex->where,
144
select_lex->order_list.elements +
145
select_lex->group_list.elements,
148
select_lex->order_list.size() +
149
select_lex->group_list.size(),
146
150
(Order*) select_lex->order_list.first,
147
151
(Order*) select_lex->group_list.first,
148
152
select_lex->having,
198
202
true an error occured
201
bool fix_inner_refs(Session *session,
202
List<Item> &all_fields,
205
bool fix_inner_refs(Session *session,
206
List<Item> &all_fields,
204
208
Item **ref_pointer_array)
206
210
Item_outer_ref *ref;
208
212
bool direct_ref= false;
210
List_iterator<Item_outer_ref> ref_it(select->inner_refs_list);
214
List<Item_outer_ref>::iterator ref_it(select->inner_refs_list.begin());
211
215
while ((ref= ref_it++))
213
217
Item *item= ref->outer_ref;
214
218
Item **item_ref= ref->ref;
215
219
Item_ref *new_ref;
217
TODO: this field item already might be present in the select list.
221
@todo this field item already might be present in the select list.
218
222
In this case instead of adding new field item we could use an
219
223
existing one. The change will lead to less operations for copying fields,
220
224
smaller temporary tables and less data passed through filesort.
222
226
if (ref_pointer_array && !ref->found_in_select_list)
224
int el= all_fields.elements;
228
int el= all_fields.size();
225
229
ref_pointer_array[el]= item;
226
230
/* Add the field item to the select list of the current select. */
227
231
all_fields.push_front(item);
636
640
(e.g. if there is a key(a,b,c) but only b < 5 (or a=2 and c < 3) is
637
641
used in the query, we drop the partial key parts from consideration).
639
if (keyuse->elements)
641
645
optimizer::KeyUse key_end,*prev,*save_pos,*use;
643
internal::my_qsort(keyuse->buffer,keyuse->elements,sizeof(optimizer::KeyUse),
647
internal::my_qsort(keyuse->buffer,keyuse->size(),sizeof(optimizer::KeyUse),
644
648
(qsort_cmp) sort_keyuse);
646
650
memset(&key_end, 0, sizeof(key_end)); /* Add for easy testing */
647
insert_dynamic(keyuse,(unsigned char*) &key_end);
651
keyuse->push_back(&key_end);
649
use= save_pos= dynamic_element(keyuse, 0, optimizer::KeyUse*);
653
use= save_pos= (optimizer::KeyUse*)keyuse->buffer;
651
655
found_eq_constant= 0;
655
for (i= 0; i < keyuse->elements-1; i++, use++)
659
for (i= 0; i < keyuse->size()-1; i++, use++)
657
661
if (! use->getUsedTables() && use->getOptimizeFlags() != KEY_OPTIMIZE_REF_OR_NULL)
658
662
use->getTable()->const_key_parts[use->getKey()]|= use->getKeypartMap();
659
663
if (use->getKey() == prev->getKey() && use->getTable() == prev->getTable())
661
if (prev->getKeypart() + 1 < use->getKeypart() ||
665
if (prev->getKeypart() + 1 < use->getKeypart() ||
662
666
((prev->getKeypart() == use->getKeypart()) && found_eq_constant))
663
667
continue; /* remove */
1901
1901
Item_cond_and *and_cond= new Item_cond_and(eq_list);
1902
1902
and_cond->quick_fix_field();
1903
1903
List<Item> *args= and_cond->argument_list();
1904
List_iterator_fast<Item_equal> it(cond_equal.current_level);
1904
List<Item_equal>::iterator it(cond_equal.current_level.begin());
1905
1905
while ((item_equal= it++))
1907
1907
item_equal->fix_length_and_dec();
1908
1908
item_equal->update_used_tables();
1909
set_if_bigger(session->lex->current_select->max_equal_elems,
1909
set_if_bigger(session->lex().current_select->max_equal_elems,
1910
1910
item_equal->members());
1912
1912
and_cond->cond_equal= cond_equal;
2472
static void propagate_cond_constants(Session *session,
2473
vector<COND_CMP>& save_list,
2472
static void propagate_cond_constants(Session *session,
2473
list<COND_CMP>& save_list,
2477
2477
if (cond->type() == Item::COND_ITEM)
2479
2479
bool and_level= ((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC;
2480
List_iterator_fast<Item> li(*((Item_cond*) cond)->argument_list());
2480
List<Item>::iterator li(((Item_cond*) cond)->argument_list()->begin());
2482
vector<COND_CMP> save;
2482
list<COND_CMP> save;
2483
2483
while ((item=li++))
2485
2485
propagate_cond_constants(session, save, and_level ? cond : item, item);
2489
2489
// Handle other found items
2490
for (vector<COND_CMP>::iterator iter= save.begin(); iter != save.end(); ++iter)
2490
for (list<COND_CMP>::iterator iter= save.begin(); iter != save.end(); ++iter)
2492
Item **args= iter->cmp_func->arguments();
2492
Item **args= iter->second->arguments();
2493
2493
if (not args[0]->const_item())
2495
change_cond_ref_to_const(session, save_list, iter->and_level,
2496
iter->and_level, args[0], args[1] );
2495
change_cond_ref_to_const(session, save, iter->first,
2496
iter->first, args[0], args[1] );
2758
2758
if (should_fix_fields)
2759
2759
cond->update_used_tables();
2761
if (! ((Item_cond*) cond)->argument_list()->elements || *cond_value != Item::COND_OK)
2761
if (! ((Item_cond*) cond)->argument_list()->size() || *cond_value != Item::COND_OK)
2762
2762
return (COND*) NULL;
2764
if (((Item_cond*) cond)->argument_list()->elements == 1)
2764
if (((Item_cond*) cond)->argument_list()->size() == 1)
2766
2766
/* Argument list contains only one element, so reduce it so a single item, then remove list */
2767
item= ((Item_cond*) cond)->argument_list()->head();
2768
((Item_cond*) cond)->argument_list()->empty();
2767
item= &((Item_cond*) cond)->argument_list()->front();
2768
((Item_cond*) cond)->argument_list()->clear();
3362
int join_read_const_table(JoinTable *tab, optimizer::Position *pos)
3365
Table *table=tab->table;
3366
table->const_table=1;
3368
table->status=STATUS_NO_RECORD;
3370
if (tab->type == AM_SYSTEM)
3372
if ((error=join_read_system(tab)))
3373
{ // Info for DESCRIBE
3374
tab->info="const row not found";
3375
/* Mark for EXPLAIN that the row was not found */
3376
pos->setFanout(0.0);
3377
pos->clearRefDependMap();
3378
if (! table->maybe_null || error > 0)
3384
if (! table->key_read &&
3385
table->covering_keys.test(tab->ref.key) &&
3386
! table->no_keyread &&
3387
(int) table->reginfo.lock_type <= (int) TL_READ_WITH_SHARED_LOCKS)
3390
table->cursor->extra(HA_EXTRA_KEYREAD);
3391
tab->index= tab->ref.key;
3393
error=join_read_const(tab);
3394
if (table->key_read)
3397
table->cursor->extra(HA_EXTRA_NO_KEYREAD);
3401
tab->info="unique row not found";
3402
/* Mark for EXPLAIN that the row was not found */
3403
pos->setFanout(0.0);
3404
pos->clearRefDependMap();
3405
if (!table->maybe_null || error > 0)
3409
if (*tab->on_expr_ref && !table->null_row)
3411
if ((table->null_row= test((*tab->on_expr_ref)->val_int() == 0)))
3412
table->mark_as_null_row();
3414
if (!table->null_row)
3415
table->maybe_null=0;
3417
/* Check appearance of new constant items in Item_equal objects */
3418
Join *join= tab->join;
3420
update_const_equal_items(join->conds, tab);
3422
for (tbl= join->select_lex->leaf_tables; tbl; tbl= tbl->next_leaf)
3424
TableList *embedded;
3425
TableList *embedding= tbl;
3428
embedded= embedding;
3429
if (embedded->on_expr)
3430
update_const_equal_items(embedded->on_expr, tab);
3431
embedding= embedded->getEmbedding();
3434
embedding->getNestedJoin()->join_list.head() == embedded);
3440
int join_read_system(JoinTable *tab)
3442
Table *table= tab->table;
3444
if (table->status & STATUS_GARBAGE) // If first read
3446
if ((error=table->cursor->read_first_row(table->getInsertRecord(),
3447
table->getShare()->getPrimaryKey())))
3449
if (error != HA_ERR_END_OF_FILE)
3450
return table->report_error(error);
3451
tab->table->mark_as_null_row();
3452
table->emptyRecord(); // Make empty record
3455
table->storeRecord();
3457
else if (!table->status) // Only happens with left join
3458
table->restoreRecord(); // restore old record
3460
return table->status ? -1 : 0;
3464
3371
Read a (constant) table when there is at most one matching row.
5210
5139
extra_length= ALIGN_SIZE(key_length)-key_length;
5213
if (hash_init(&hash, &my_charset_bin, (uint32_t) cursor->stats.records, 0,
5214
key_length, (hash_get_key) 0, 0, 0))
5219
cursor->startTableScan(1);
5142
if (hash_init(&hash, &my_charset_bin, (uint32_t) cursor.stats.records, 0, key_length, (hash_get_key) 0, 0, 0))
5145
if ((error= cursor.startTableScan(1)))
5220
5148
key_pos= &key_buffer[0];
5223
unsigned char *org_key_pos;
5224
5151
if (session->getKilled())
5226
5153
session->send_kill_message();
5230
if ((error=cursor->rnd_next(record)))
5157
if ((error=cursor.rnd_next(record)))
5232
5159
if (error == HA_ERR_RECORD_DELETED)
5858
5784
List<Item> &all_fields)
5861
List_iterator_fast<Item> li(all_fields);
5787
List<Item>::iterator li(all_fields.begin());
5862
5788
CopyField *copy= NULL;
5863
res_selected_fields.empty();
5864
res_all_fields.empty();
5865
List_iterator_fast<Item> itr(res_all_fields);
5789
res_selected_fields.clear();
5790
res_all_fields.clear();
5791
List<Item>::iterator itr(res_all_fields.begin());
5866
5792
List<Item> extra_funcs;
5867
uint32_t i, border= all_fields.elements - elements;
5793
uint32_t i, border= all_fields.size() - elements;
5869
5795
if (param->field_count &&
5870
!(copy=param->copy_field= new CopyField[param->field_count]))
5796
!(copy= param->copy_field= new CopyField[param->field_count]))
5873
param->copy_funcs.empty();
5799
param->copy_funcs.clear();
5874
5800
for (i= 0; (pos= li++); i++)
5939
5864
!real_pos->with_sum_func)
5940
5865
{ // Save for send fields
5943
In most cases this result will be sent to the user.
5868
@todo In most cases this result will be sent to the user.
5944
5869
This should be changed to use copy_int or copy_real depending
5945
5870
on how the value is to be used: In some cases this may be an
5946
5871
argument in a group function, like: IF(ISNULL(col),0,COUNT(*))
5948
if (!(pos=new Item_copy_string(pos)))
5873
pos=new Item_copy_string(pos);
5950
5874
if (i < border) // HAVING, order_st and GROUP BY
5952
if (extra_funcs.push_back(pos))
5955
else if (param->copy_funcs.push_back(pos))
5875
extra_funcs.push_back(pos);
5877
param->copy_funcs.push_back(pos);
5958
5879
res_all_fields.push_back(pos);
5959
ref_pointer_array[((i < border)? all_fields.elements-i-1 : i-border)]=
5880
ref_pointer_array[((i < border)? all_fields.size()-i-1 : i-border)]=
5962
5883
param->copy_field_end= copy;
6102
6022
uint32_t elements,
6103
6023
List<Item> &all_fields)
6105
List_iterator_fast<Item> it(all_fields);
6025
List<Item>::iterator it(all_fields.begin());
6106
6026
Item *item, *new_item;
6107
res_selected_fields.empty();
6108
res_all_fields.empty();
6027
res_selected_fields.clear();
6028
res_all_fields.clear();
6110
uint32_t i, border= all_fields.elements - elements;
6030
uint32_t i, border= all_fields.size() - elements;
6111
6031
for (i= 0; (item= it++); i++)
6113
6033
res_all_fields.push_back(new_item= item->get_tmp_table_item(session));
6114
ref_pointer_array[((i < border)? all_fields.elements-i-1 : i-border)]=
6034
ref_pointer_array[((i < border)? all_fields.size()-i-1 : i-border)]=
6118
List_iterator_fast<Item> itr(res_all_fields);
6038
List<Item>::iterator itr(res_all_fields.begin());
6119
6039
for (i= 0; i < border; i++)
6121
6041
itr.sublist(res_selected_fields, elements);
6349
6269
@param session thread Cursor
6350
6270
@param str string where table should be printed
6351
6271
@param tables list of tables in join
6352
@query_type type of the query is being generated
6354
6273
void print_join(Session *session, String *str,
6355
List<TableList> *tables, enum_query_type)
6274
List<TableList> *tables)
6357
6276
/* List is reversed => we should reverse it before using */
6358
List_iterator_fast<TableList> ti(*tables);
6359
TableList **table= (TableList **)session->alloc(sizeof(TableList*) *
6277
List<TableList>::iterator ti(tables->begin());
6278
TableList **table= (TableList **)session->getMemRoot()->allocate(sizeof(TableList*) *
6361
6280
if (table == 0)
6362
6281
return; // out of memory
6364
for (TableList **t= table + (tables->elements - 1); t >= table; t--)
6283
for (TableList **t= table + (tables->size() - 1); t >= table; t--)
6366
assert(tables->elements >= 1);
6367
print_table_array(session, str, table, table + tables->elements);
6285
assert(tables->size() >= 1);
6286
print_table_array(session, str, table, table + tables->size());
6370
void Select_Lex::print(Session *session, String *str, enum_query_type query_type)
6289
void Select_Lex::print(Session *session, String *str)
6372
6291
/* QQ: session may not be set for sub queries, but this should be fixed */
6373
6292
if(not session)
6463
6382
str->append(STRING_WITH_LEN(" having "));
6464
6383
if (cur_having)
6465
cur_having->print(str, query_type);
6384
cur_having->print(str);
6467
6386
str->append(having_value != Item::COND_FALSE ? "1" : "0");
6470
if (order_list.elements)
6389
if (order_list.size())
6472
6391
str->append(STRING_WITH_LEN(" order by "));
6473
print_order(str, (Order *) order_list.first, query_type);
6392
print_order(str, (Order *) order_list.first);
6477
print_limit(session, str, query_type);
6396
print_limit(session, str);
6479
6398
// PROCEDURE unsupported here