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"
55
#include "drizzled/plugin/storage_engine.h"
57
#include "drizzled/sql_union.h"
58
#include "drizzled/optimizer/key_field.h"
59
#include "drizzled/optimizer/position.h"
60
#include "drizzled/optimizer/sargable_param.h"
61
#include "drizzled/optimizer/key_use.h"
62
#include "drizzled/optimizer/range.h"
63
#include "drizzled/optimizer/quick_range_select.h"
64
#include "drizzled/optimizer/quick_ror_intersect_select.h"
66
#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>
68
72
using namespace std;
73
76
static int sort_keyuse(optimizer::KeyUse *a, optimizer::KeyUse *b);
74
77
static COND *build_equal_items(Session *session, COND *cond,
199
200
true an error occured
202
bool fix_inner_refs(Session *session,
203
List<Item> &all_fields,
203
bool fix_inner_refs(Session *session,
204
List<Item> &all_fields,
205
206
Item **ref_pointer_array)
207
208
Item_outer_ref *ref;
209
210
bool direct_ref= false;
211
List_iterator<Item_outer_ref> ref_it(select->inner_refs_list);
212
List<Item_outer_ref>::iterator ref_it(select->inner_refs_list.begin());
212
213
while ((ref= ref_it++))
214
215
Item *item= ref->outer_ref;
215
216
Item **item_ref= ref->ref;
216
217
Item_ref *new_ref;
218
TODO: this field item already might be present in the select list.
219
@todo this field item already might be present in the select list.
219
220
In this case instead of adding new field item we could use an
220
221
existing one. The change will lead to less operations for copying fields,
221
222
smaller temporary tables and less data passed through filesort.
223
224
if (ref_pointer_array && !ref->found_in_select_list)
225
int el= all_fields.elements;
226
int el= all_fields.size();
226
227
ref_pointer_array[el]= item;
227
228
/* Add the field item to the select list of the current select. */
228
229
all_fields.push_front(item);
637
638
(e.g. if there is a key(a,b,c) but only b < 5 (or a=2 and c < 3) is
638
639
used in the query, we drop the partial key parts from consideration).
640
if (keyuse->elements)
642
643
optimizer::KeyUse key_end,*prev,*save_pos,*use;
644
internal::my_qsort(keyuse->buffer,keyuse->elements,sizeof(optimizer::KeyUse),
645
internal::my_qsort(keyuse->buffer,keyuse->size(),sizeof(optimizer::KeyUse),
645
646
(qsort_cmp) sort_keyuse);
647
648
memset(&key_end, 0, sizeof(key_end)); /* Add for easy testing */
648
insert_dynamic(keyuse,(unsigned char*) &key_end);
649
keyuse->push_back(&key_end);
650
use= save_pos= dynamic_element(keyuse, 0, optimizer::KeyUse*);
651
use= save_pos= (optimizer::KeyUse*)keyuse->buffer;
652
653
found_eq_constant= 0;
656
for (i= 0; i < keyuse->elements-1; i++, use++)
657
for (i= 0; i < keyuse->size()-1; i++, use++)
658
659
if (! use->getUsedTables() && use->getOptimizeFlags() != KEY_OPTIMIZE_REF_OR_NULL)
659
660
use->getTable()->const_key_parts[use->getKey()]|= use->getKeypartMap();
660
661
if (use->getKey() == prev->getKey() && use->getTable() == prev->getTable())
662
if (prev->getKeypart() + 1 < use->getKeypart() ||
663
if (prev->getKeypart() + 1 < use->getKeypart() ||
663
664
((prev->getKeypart() == use->getKeypart()) && found_eq_constant))
664
665
continue; /* remove */
1902
1896
Item_cond_and *and_cond= new Item_cond_and(eq_list);
1903
1897
and_cond->quick_fix_field();
1904
1898
List<Item> *args= and_cond->argument_list();
1905
List_iterator_fast<Item_equal> it(cond_equal.current_level);
1899
List<Item_equal>::iterator it(cond_equal.current_level.begin());
1906
1900
while ((item_equal= it++))
1908
1902
item_equal->fix_length_and_dec();
1909
1903
item_equal->update_used_tables();
1910
set_if_bigger(session->lex->current_select->max_equal_elems,
1904
set_if_bigger(session->lex().current_select->max_equal_elems,
1911
1905
item_equal->members());
1913
1907
and_cond->cond_equal= cond_equal;
2759
2753
if (should_fix_fields)
2760
2754
cond->update_used_tables();
2762
if (! ((Item_cond*) cond)->argument_list()->elements || *cond_value != Item::COND_OK)
2756
if (! ((Item_cond*) cond)->argument_list()->size() || *cond_value != Item::COND_OK)
2763
2757
return (COND*) NULL;
2765
if (((Item_cond*) cond)->argument_list()->elements == 1)
2759
if (((Item_cond*) cond)->argument_list()->size() == 1)
2767
2761
/* Argument list contains only one element, so reduce it so a single item, then remove list */
2768
item= ((Item_cond*) cond)->argument_list()->head();
2769
((Item_cond*) cond)->argument_list()->empty();
2762
item= &((Item_cond*) cond)->argument_list()->front();
2763
((Item_cond*) cond)->argument_list()->clear();
5144
5129
extra_length= ALIGN_SIZE(key_length)-key_length;
5147
if (hash_init(&hash, &my_charset_bin, (uint32_t) cursor->stats.records, 0,
5148
key_length, (hash_get_key) 0, 0, 0))
5132
if (hash_init(&hash, &my_charset_bin, (uint32_t) cursor.stats.records, 0, key_length, (hash_get_key) 0, 0, 0))
5153
if ((error= cursor->startTableScan(1)))
5135
if ((error= cursor.startTableScan(1)))
5156
5138
key_pos= &key_buffer[0];
5159
unsigned char *org_key_pos;
5160
5141
if (session->getKilled())
5162
5143
session->send_kill_message();
5166
if ((error=cursor->rnd_next(record)))
5147
if ((error=cursor.rnd_next(record)))
5168
5149
if (error == HA_ERR_RECORD_DELETED)
5794
5774
List<Item> &all_fields)
5797
List_iterator_fast<Item> li(all_fields);
5777
List<Item>::iterator li(all_fields.begin());
5798
5778
CopyField *copy= NULL;
5799
res_selected_fields.empty();
5800
res_all_fields.empty();
5801
List_iterator_fast<Item> itr(res_all_fields);
5779
res_selected_fields.clear();
5780
res_all_fields.clear();
5781
List<Item>::iterator itr(res_all_fields.begin());
5802
5782
List<Item> extra_funcs;
5803
uint32_t i, border= all_fields.elements - elements;
5783
uint32_t i, border= all_fields.size() - elements;
5805
5785
if (param->field_count &&
5806
!(copy=param->copy_field= new CopyField[param->field_count]))
5786
!(copy= param->copy_field= new CopyField[param->field_count]))
5809
param->copy_funcs.empty();
5789
param->copy_funcs.clear();
5810
5790
for (i= 0; (pos= li++); i++)
5875
5854
!real_pos->with_sum_func)
5876
5855
{ // Save for send fields
5879
In most cases this result will be sent to the user.
5858
@todo In most cases this result will be sent to the user.
5880
5859
This should be changed to use copy_int or copy_real depending
5881
5860
on how the value is to be used: In some cases this may be an
5882
5861
argument in a group function, like: IF(ISNULL(col),0,COUNT(*))
5884
if (!(pos=new Item_copy_string(pos)))
5863
pos=new Item_copy_string(pos);
5886
5864
if (i < border) // HAVING, order_st and GROUP BY
5888
if (extra_funcs.push_back(pos))
5891
else if (param->copy_funcs.push_back(pos))
5865
extra_funcs.push_back(pos);
5867
param->copy_funcs.push_back(pos);
5894
5869
res_all_fields.push_back(pos);
5895
ref_pointer_array[((i < border)? all_fields.elements-i-1 : i-border)]=
5870
ref_pointer_array[((i < border)? all_fields.size()-i-1 : i-border)]=
5898
5873
param->copy_field_end= copy;
6038
6012
uint32_t elements,
6039
6013
List<Item> &all_fields)
6041
List_iterator_fast<Item> it(all_fields);
6015
List<Item>::iterator it(all_fields.begin());
6042
6016
Item *item, *new_item;
6043
res_selected_fields.empty();
6044
res_all_fields.empty();
6017
res_selected_fields.clear();
6018
res_all_fields.clear();
6046
uint32_t i, border= all_fields.elements - elements;
6020
uint32_t i, border= all_fields.size() - elements;
6047
6021
for (i= 0; (item= it++); i++)
6049
6023
res_all_fields.push_back(new_item= item->get_tmp_table_item(session));
6050
ref_pointer_array[((i < border)? all_fields.elements-i-1 : i-border)]=
6024
ref_pointer_array[((i < border)? all_fields.size()-i-1 : i-border)]=
6054
List_iterator_fast<Item> itr(res_all_fields);
6028
List<Item>::iterator itr(res_all_fields.begin());
6055
6029
for (i= 0; i < border; i++)
6057
6031
itr.sublist(res_selected_fields, elements);
6285
6259
@param session thread Cursor
6286
6260
@param str string where table should be printed
6287
6261
@param tables list of tables in join
6288
@query_type type of the query is being generated
6290
6263
void print_join(Session *session, String *str,
6291
List<TableList> *tables, enum_query_type)
6264
List<TableList> *tables)
6293
6266
/* List is reversed => we should reverse it before using */
6294
List_iterator_fast<TableList> ti(*tables);
6267
List<TableList>::iterator ti(tables->begin());
6295
6268
TableList **table= (TableList **)session->getMemRoot()->allocate(sizeof(TableList*) *
6297
6270
if (table == 0)
6298
6271
return; // out of memory
6300
for (TableList **t= table + (tables->elements - 1); t >= table; t--)
6273
for (TableList **t= table + (tables->size() - 1); t >= table; t--)
6302
assert(tables->elements >= 1);
6303
print_table_array(session, str, table, table + tables->elements);
6275
assert(tables->size() >= 1);
6276
print_table_array(session, str, table, table + tables->size());
6306
void Select_Lex::print(Session *session, String *str, enum_query_type query_type)
6279
void Select_Lex::print(Session *session, String *str)
6308
6281
/* QQ: session may not be set for sub queries, but this should be fixed */
6309
6282
if(not session)
6399
6372
str->append(STRING_WITH_LEN(" having "));
6400
6373
if (cur_having)
6401
cur_having->print(str, query_type);
6374
cur_having->print(str);
6403
6376
str->append(having_value != Item::COND_FALSE ? "1" : "0");
6406
if (order_list.elements)
6379
if (order_list.size())
6408
6381
str->append(STRING_WITH_LEN(" order by "));
6409
print_order(str, (Order *) order_list.first, query_type);
6382
print_order(str, (Order *) order_list.first);
6413
print_limit(session, str, query_type);
6386
print_limit(session, str);
6415
6388
// PROCEDURE unsupported here