index_merge implementation using Unique class, to be merged into 5.0
This commit is contained in:
parent
0466c25078
commit
1c61a92ba7
@ -110,6 +110,7 @@ serg@serg.mylan
|
|||||||
serg@serg.mysql.com
|
serg@serg.mysql.com
|
||||||
serg@sergbook.mylan
|
serg@sergbook.mylan
|
||||||
serg@sergbook.mysql.com
|
serg@sergbook.mysql.com
|
||||||
|
sergefp@mysql.com
|
||||||
sinisa@rhols221.adsl.netsonic.fi
|
sinisa@rhols221.adsl.netsonic.fi
|
||||||
tfr@beta.frontier86.ee
|
tfr@beta.frontier86.ee
|
||||||
tfr@indrek.tfr.cafe.ee
|
tfr@indrek.tfr.cafe.ee
|
||||||
|
@ -49,7 +49,8 @@ static int merge_index(SORTPARAM *param,uchar *sort_buffer,
|
|||||||
BUFFPEK *buffpek,
|
BUFFPEK *buffpek,
|
||||||
uint maxbuffer,IO_CACHE *tempfile,
|
uint maxbuffer,IO_CACHE *tempfile,
|
||||||
IO_CACHE *outfile);
|
IO_CACHE *outfile);
|
||||||
static bool save_index(SORTPARAM *param,uchar **sort_keys, uint count);
|
static bool save_index(SORTPARAM *param,uchar **sort_keys, uint count,
|
||||||
|
FILESORT_INFO *table_sort);
|
||||||
static uint sortlength(SORT_FIELD *sortorder, uint s_length,
|
static uint sortlength(SORT_FIELD *sortorder, uint s_length,
|
||||||
bool *multi_byte_charset);
|
bool *multi_byte_charset);
|
||||||
static SORT_ADDON_FIELD *get_addon_fields(THD *thd, Field **ptabfield,
|
static SORT_ADDON_FIELD *get_addon_fields(THD *thd, Field **ptabfield,
|
||||||
@ -86,6 +87,8 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
|
|||||||
#ifdef SKIP_DBUG_IN_FILESORT
|
#ifdef SKIP_DBUG_IN_FILESORT
|
||||||
DBUG_PUSH(""); /* No DBUG here */
|
DBUG_PUSH(""); /* No DBUG here */
|
||||||
#endif
|
#endif
|
||||||
|
FILESORT_INFO table_sort;
|
||||||
|
bzero(&table_sort, sizeof(FILESORT_INFO));
|
||||||
|
|
||||||
outfile= table->sort.io_cache;
|
outfile= table->sort.io_cache;
|
||||||
my_b_clear(&tempfile);
|
my_b_clear(&tempfile);
|
||||||
@ -108,14 +111,15 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
|
|||||||
param.sort_length,
|
param.sort_length,
|
||||||
¶m.addon_length);
|
¶m.addon_length);
|
||||||
}
|
}
|
||||||
table->sort.addon_buf= 0;
|
|
||||||
table->sort.addon_length= param.addon_length;
|
table_sort.addon_buf= 0;
|
||||||
table->sort.addon_field= param.addon_field;
|
table_sort.addon_length= param.addon_length;
|
||||||
table->sort.unpack= unpack_addon_fields;
|
table_sort.addon_field= param.addon_field;
|
||||||
|
table_sort.unpack= unpack_addon_fields;
|
||||||
if (param.addon_field)
|
if (param.addon_field)
|
||||||
{
|
{
|
||||||
param.res_length= param.addon_length;
|
param.res_length= param.addon_length;
|
||||||
if (!(table->sort.addon_buf= (byte *) my_malloc(param.addon_length,
|
if (!(table_sort.addon_buf= (byte *) my_malloc(param.addon_length,
|
||||||
MYF(MY_WME))))
|
MYF(MY_WME))))
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
@ -194,7 +198,7 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
|
|||||||
|
|
||||||
if (maxbuffer == 0) // The whole set is in memory
|
if (maxbuffer == 0) // The whole set is in memory
|
||||||
{
|
{
|
||||||
if (save_index(¶m,sort_keys,(uint) records))
|
if (save_index(¶m,sort_keys,(uint) records, &table_sort))
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -257,6 +261,8 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
|
|||||||
#ifdef SKIP_DBUG_IN_FILESORT
|
#ifdef SKIP_DBUG_IN_FILESORT
|
||||||
DBUG_POP(); /* Ok to DBUG */
|
DBUG_POP(); /* Ok to DBUG */
|
||||||
#endif
|
#endif
|
||||||
|
memcpy(&table->sort, &table_sort, sizeof(FILESORT_INFO));
|
||||||
|
table->sort.io_cache= outfile;
|
||||||
DBUG_PRINT("exit",("records: %ld",records));
|
DBUG_PRINT("exit",("records: %ld",records));
|
||||||
DBUG_RETURN(error ? HA_POS_ERROR : records);
|
DBUG_RETURN(error ? HA_POS_ERROR : records);
|
||||||
} /* filesort */
|
} /* filesort */
|
||||||
@ -360,12 +366,24 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
|
|||||||
current_thd->variables.read_buff_size);
|
current_thd->variables.read_buff_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
READ_RECORD read_record_info;
|
||||||
|
if (quick_select)
|
||||||
|
{
|
||||||
|
if (select->quick->reset())
|
||||||
|
DBUG_RETURN(HA_POS_ERROR);
|
||||||
|
init_read_record(&read_record_info, current_thd, select->quick->head,
|
||||||
|
select, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
if (quick_select)
|
if (quick_select)
|
||||||
{
|
{
|
||||||
if ((error=select->quick->get_next()))
|
if ((error= read_record_info.read_record(&read_record_info)))
|
||||||
|
{
|
||||||
|
error= HA_ERR_END_OF_FILE;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
file->position(sort_form->record[0]);
|
file->position(sort_form->record[0]);
|
||||||
}
|
}
|
||||||
else /* Not quick-select */
|
else /* Not quick-select */
|
||||||
@ -393,6 +411,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
|
|||||||
if (error && error != HA_ERR_RECORD_DELETED)
|
if (error && error != HA_ERR_RECORD_DELETED)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*killed)
|
if (*killed)
|
||||||
{
|
{
|
||||||
DBUG_PRINT("info",("Sort killed by user"));
|
DBUG_PRINT("info",("Sort killed by user"));
|
||||||
@ -426,8 +445,14 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
|
|||||||
else
|
else
|
||||||
file->unlock_row();
|
file->unlock_row();
|
||||||
}
|
}
|
||||||
|
if (quick_select)
|
||||||
|
end_read_record(&read_record_info);
|
||||||
|
else
|
||||||
|
{
|
||||||
(void) file->extra(HA_EXTRA_NO_CACHE); /* End cacheing of records */
|
(void) file->extra(HA_EXTRA_NO_CACHE); /* End cacheing of records */
|
||||||
file->rnd_end();
|
file->rnd_end();
|
||||||
|
}
|
||||||
|
|
||||||
DBUG_PRINT("test",("error: %d indexpos: %d",error,indexpos));
|
DBUG_PRINT("test",("error: %d indexpos: %d",error,indexpos));
|
||||||
if (error != HA_ERR_END_OF_FILE)
|
if (error != HA_ERR_END_OF_FILE)
|
||||||
{
|
{
|
||||||
@ -665,8 +690,8 @@ static void make_sortkey(register SORTPARAM *param,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool save_index(SORTPARAM *param, uchar **sort_keys, uint count,
|
||||||
static bool save_index(SORTPARAM *param, uchar **sort_keys, uint count)
|
FILESORT_INFO *table_sort)
|
||||||
{
|
{
|
||||||
uint offset,res_length;
|
uint offset,res_length;
|
||||||
byte *to;
|
byte *to;
|
||||||
@ -677,7 +702,7 @@ static bool save_index(SORTPARAM *param, uchar **sort_keys, uint count)
|
|||||||
offset= param->rec_length-res_length;
|
offset= param->rec_length-res_length;
|
||||||
if ((ha_rows) count > param->max_rows)
|
if ((ha_rows) count > param->max_rows)
|
||||||
count=(uint) param->max_rows;
|
count=(uint) param->max_rows;
|
||||||
if (!(to= param->sort_form->sort.record_pointers=
|
if (!(to= table_sort->record_pointers=
|
||||||
(byte*) my_malloc(res_length*count, MYF(MY_WME))))
|
(byte*) my_malloc(res_length*count, MYF(MY_WME))))
|
||||||
DBUG_RETURN(1); /* purecov: inspected */
|
DBUG_RETURN(1); /* purecov: inspected */
|
||||||
for (uchar **end= sort_keys+count ; sort_keys != end ; sort_keys++)
|
for (uchar **end= sort_keys+count ; sort_keys != end ; sort_keys++)
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
** Create a FT or QUICK RANGE based on a key
|
** Create a FT or QUICK RANGE based on a key
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
QUICK_SELECT *get_ft_or_quick_select_for_ref(TABLE *table, JOIN_TAB *tab)
|
QUICK_RANGE_SELECT *get_ft_or_quick_select_for_ref(TABLE *table, JOIN_TAB *tab)
|
||||||
{
|
{
|
||||||
if (tab->type == JT_FT)
|
if (tab->type == JT_FT)
|
||||||
return new FT_SELECT(table, &tab->ref);
|
return new FT_SELECT(table, &tab->ref);
|
||||||
|
@ -24,17 +24,18 @@
|
|||||||
#pragma interface /* gcc class implementation */
|
#pragma interface /* gcc class implementation */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class FT_SELECT: public QUICK_SELECT {
|
class FT_SELECT: public QUICK_RANGE_SELECT {
|
||||||
public:
|
public:
|
||||||
TABLE_REF *ref;
|
TABLE_REF *ref;
|
||||||
|
|
||||||
FT_SELECT(TABLE *table, TABLE_REF *tref) :
|
FT_SELECT(TABLE *table, TABLE_REF *tref) :
|
||||||
QUICK_SELECT (table,tref->key,1), ref(tref) { init(); }
|
QUICK_RANGE_SELECT (table,tref->key,1), ref(tref) { init(); }
|
||||||
|
|
||||||
int init() { return error=file->ft_init(); }
|
int init() { QUICK_RANGE_SELECT::init(); return (error=file->ft_init()); }
|
||||||
int get_next() { return error=file->ft_read(record); }
|
int get_next() { return error=file->ft_read(record); }
|
||||||
|
int get_type() { return QS_TYPE_FULLTEXT; }
|
||||||
};
|
};
|
||||||
|
|
||||||
QUICK_SELECT *get_ft_or_quick_select_for_ref(TABLE *table, JOIN_TAB *tab);
|
QUICK_RANGE_SELECT *get_ft_or_quick_select_for_ref(TABLE *table, JOIN_TAB *tab);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
795
sql/opt_range.cc
795
sql/opt_range.cc
File diff suppressed because it is too large
Load Diff
132
sql/opt_range.h
132
sql/opt_range.h
@ -65,48 +65,142 @@ class QUICK_RANGE :public Sql_alloc {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//class INDEX_MERGE;
|
||||||
|
|
||||||
class QUICK_SELECT {
|
/*
|
||||||
|
Quick select interface.
|
||||||
|
This class is parent for all QUICK_*_SELECT and FT_SELECT classes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class QUICK_SELECT_I
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
bool next,dont_free;
|
ha_rows records; /* estimate of # of records to be retrieved */
|
||||||
int error;
|
double read_time; /* time to perform this retrieval */
|
||||||
uint index, max_used_key_length, used_key_parts;
|
|
||||||
TABLE *head;
|
TABLE *head;
|
||||||
|
|
||||||
|
/*
|
||||||
|
the only index this quick select uses, or MAX_KEY for
|
||||||
|
QUICK_INDEX_MERGE_SELECT
|
||||||
|
*/
|
||||||
|
uint index;
|
||||||
|
uint max_used_key_length, used_key_parts;
|
||||||
|
|
||||||
|
QUICK_SELECT_I();
|
||||||
|
virtual ~QUICK_SELECT_I(){};
|
||||||
|
virtual int init() = 0;
|
||||||
|
virtual int reset(void) = 0;
|
||||||
|
virtual int get_next() = 0; /* get next record to retrieve */
|
||||||
|
virtual bool reverse_sorted() = 0;
|
||||||
|
virtual bool unique_key_range() { return false; }
|
||||||
|
|
||||||
|
enum {
|
||||||
|
QS_TYPE_RANGE = 0,
|
||||||
|
QS_TYPE_INDEX_MERGE = 1,
|
||||||
|
QS_TYPE_RANGE_DESC = 2,
|
||||||
|
QS_TYPE_FULLTEXT = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Get type of this quick select - one of the QS_* values */
|
||||||
|
virtual int get_type() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct st_qsel_param;
|
||||||
|
class SEL_ARG;
|
||||||
|
|
||||||
|
class QUICK_RANGE_SELECT : public QUICK_SELECT_I
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
bool next,dont_free;
|
||||||
|
public:
|
||||||
|
int error;
|
||||||
handler *file;
|
handler *file;
|
||||||
byte *record;
|
byte *record;
|
||||||
|
protected:
|
||||||
|
friend void print_quick_sel_range(QUICK_RANGE_SELECT *quick,
|
||||||
|
key_map needed_reg);
|
||||||
|
friend QUICK_RANGE_SELECT *get_quick_select_for_ref(TABLE *table,
|
||||||
|
struct st_table_ref *ref);
|
||||||
|
friend bool get_quick_keys(struct st_qsel_param *param,
|
||||||
|
QUICK_RANGE_SELECT *quick,KEY_PART *key,
|
||||||
|
SEL_ARG *key_tree,char *min_key,uint min_key_flag,
|
||||||
|
char *max_key, uint max_key_flag);
|
||||||
|
friend QUICK_RANGE_SELECT *get_quick_select(struct st_qsel_param*,uint idx,
|
||||||
|
SEL_ARG *key_tree,
|
||||||
|
MEM_ROOT *alloc);
|
||||||
|
friend class QUICK_SELECT_DESC;
|
||||||
|
|
||||||
List<QUICK_RANGE> ranges;
|
List<QUICK_RANGE> ranges;
|
||||||
List_iterator<QUICK_RANGE> it;
|
List_iterator<QUICK_RANGE> it;
|
||||||
QUICK_RANGE *range;
|
QUICK_RANGE *range;
|
||||||
MEM_ROOT alloc;
|
MEM_ROOT alloc;
|
||||||
|
|
||||||
KEY_PART *key_parts;
|
KEY_PART *key_parts;
|
||||||
ha_rows records;
|
|
||||||
double read_time;
|
|
||||||
|
|
||||||
QUICK_SELECT(TABLE *table,uint index_arg,bool no_alloc=0);
|
|
||||||
virtual ~QUICK_SELECT();
|
|
||||||
void reset(void) { next=0; it.rewind(); }
|
|
||||||
int init() { return error=file->index_init(index); }
|
|
||||||
virtual int get_next();
|
|
||||||
virtual bool reverse_sorted() { return 0; }
|
|
||||||
int cmp_next(QUICK_RANGE *range);
|
int cmp_next(QUICK_RANGE *range);
|
||||||
|
public:
|
||||||
|
QUICK_RANGE_SELECT(TABLE *table,uint index_arg,bool no_alloc=0,
|
||||||
|
MEM_ROOT *parent_alloc=NULL);
|
||||||
|
~QUICK_RANGE_SELECT();
|
||||||
|
|
||||||
|
int reset(void) { next=0; it.rewind(); return 0; }
|
||||||
|
int init();
|
||||||
|
int get_next();
|
||||||
|
bool reverse_sorted() { return 0; }
|
||||||
bool unique_key_range();
|
bool unique_key_range();
|
||||||
|
int get_type() { return QS_TYPE_RANGE; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Index merge quick select.
|
||||||
|
It is implemented as a container for several QUICK_RANGE_SELECTs.
|
||||||
|
*/
|
||||||
|
|
||||||
class QUICK_SELECT_DESC: public QUICK_SELECT
|
class QUICK_INDEX_MERGE_SELECT : public QUICK_SELECT_I
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QUICK_SELECT_DESC(QUICK_SELECT *q, uint used_key_parts);
|
QUICK_INDEX_MERGE_SELECT(THD *thd, TABLE *table);
|
||||||
|
~QUICK_INDEX_MERGE_SELECT();
|
||||||
|
|
||||||
|
int init();
|
||||||
|
int reset(void);
|
||||||
|
int get_next();
|
||||||
|
bool reverse_sorted() { return false; }
|
||||||
|
bool unique_key_range() { return false; }
|
||||||
|
int get_type() { return QS_TYPE_INDEX_MERGE; }
|
||||||
|
|
||||||
|
bool push_quick_back(QUICK_RANGE_SELECT *quick_sel_range);
|
||||||
|
|
||||||
|
/* range quick selects this index_merge read consists of */
|
||||||
|
List<QUICK_RANGE_SELECT> quick_selects;
|
||||||
|
|
||||||
|
/* quick select which is currently used for rows retrieval */
|
||||||
|
List_iterator_fast<QUICK_RANGE_SELECT> cur_quick_it;
|
||||||
|
QUICK_RANGE_SELECT* cur_quick_select;
|
||||||
|
|
||||||
|
/* last element in quick_selects list. */
|
||||||
|
QUICK_RANGE_SELECT* last_quick_select;
|
||||||
|
|
||||||
|
Unique *unique;
|
||||||
|
MEM_ROOT alloc;
|
||||||
|
|
||||||
|
THD *thd;
|
||||||
|
int prepare_unique();
|
||||||
|
bool reset_called;
|
||||||
|
};
|
||||||
|
|
||||||
|
class QUICK_SELECT_DESC: public QUICK_RANGE_SELECT
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QUICK_SELECT_DESC(QUICK_RANGE_SELECT *q, uint used_key_parts);
|
||||||
int get_next();
|
int get_next();
|
||||||
bool reverse_sorted() { return 1; }
|
bool reverse_sorted() { return 1; }
|
||||||
|
int get_type() { return QS_TYPE_RANGE_DESC; }
|
||||||
private:
|
private:
|
||||||
int cmp_prev(QUICK_RANGE *range);
|
int cmp_prev(QUICK_RANGE *range);
|
||||||
bool range_reads_after_key(QUICK_RANGE *range);
|
bool range_reads_after_key(QUICK_RANGE *range);
|
||||||
#ifdef NOT_USED
|
#ifdef NOT_USED
|
||||||
bool test_if_null_range(QUICK_RANGE *range, uint used_key_parts);
|
bool test_if_null_range(QUICK_RANGE *range, uint used_key_parts);
|
||||||
#endif
|
#endif
|
||||||
void reset(void) { next=0; rev_it.rewind(); }
|
int reset(void) { next=0; rev_it.rewind(); return 0; }
|
||||||
List<QUICK_RANGE> rev_ranges;
|
List<QUICK_RANGE> rev_ranges;
|
||||||
List_iterator<QUICK_RANGE> rev_it;
|
List_iterator<QUICK_RANGE> rev_it;
|
||||||
};
|
};
|
||||||
@ -114,7 +208,7 @@ private:
|
|||||||
|
|
||||||
class SQL_SELECT :public Sql_alloc {
|
class SQL_SELECT :public Sql_alloc {
|
||||||
public:
|
public:
|
||||||
QUICK_SELECT *quick; // If quick-select used
|
QUICK_SELECT_I *quick; // If quick-select used
|
||||||
COND *cond; // where condition
|
COND *cond; // where condition
|
||||||
TABLE *head;
|
TABLE *head;
|
||||||
IO_CACHE file; // Positions to used records
|
IO_CACHE file; // Positions to used records
|
||||||
@ -134,6 +228,6 @@ class SQL_SELECT :public Sql_alloc {
|
|||||||
bool force_quick_range=0);
|
bool force_quick_range=0);
|
||||||
};
|
};
|
||||||
|
|
||||||
QUICK_SELECT *get_quick_select_for_ref(TABLE *table, struct st_table_ref *ref);
|
QUICK_RANGE_SELECT *get_quick_select_for_ref(TABLE *table, struct st_table_ref *ref);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -98,7 +98,8 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (select && select->quick)
|
else if (select && select->quick &&
|
||||||
|
(select->quick->get_type() != QUICK_SELECT_I::QS_TYPE_INDEX_MERGE))
|
||||||
{
|
{
|
||||||
DBUG_PRINT("info",("using rr_quick"));
|
DBUG_PRINT("info",("using rr_quick"));
|
||||||
info->read_record=rr_quick;
|
info->read_record=rr_quick;
|
||||||
|
@ -537,8 +537,8 @@ int THD::send_explain_fields(select_result *result)
|
|||||||
item->maybe_null=1;
|
item->maybe_null=1;
|
||||||
field_list.push_back(item=new Item_empty_string("key",NAME_LEN));
|
field_list.push_back(item=new Item_empty_string("key",NAME_LEN));
|
||||||
item->maybe_null=1;
|
item->maybe_null=1;
|
||||||
field_list.push_back(item=new Item_return_int("key_len",3,
|
field_list.push_back(item=new Item_empty_string("key_len",
|
||||||
MYSQL_TYPE_LONGLONG));
|
NAME_LEN*MAX_KEY));
|
||||||
item->maybe_null=1;
|
item->maybe_null=1;
|
||||||
field_list.push_back(item=new Item_empty_string("ref",
|
field_list.push_back(item=new Item_empty_string("ref",
|
||||||
NAME_LEN*MAX_REF_PARTS));
|
NAME_LEN*MAX_REF_PARTS));
|
||||||
|
@ -135,6 +135,12 @@ public:
|
|||||||
last= &first;
|
last= &first;
|
||||||
return tmp->info;
|
return tmp->info;
|
||||||
}
|
}
|
||||||
|
inline void concat(base_list *list)
|
||||||
|
{
|
||||||
|
*last= list->first;
|
||||||
|
last= list->last;
|
||||||
|
elements+= list->elements;
|
||||||
|
}
|
||||||
inline list_node* last_node() { return *last; }
|
inline list_node* last_node() { return *last; }
|
||||||
inline list_node* first_node() { return first;}
|
inline list_node* first_node() { return first;}
|
||||||
inline void *head() { return first->info; }
|
inline void *head() { return first->info; }
|
||||||
@ -255,6 +261,7 @@ public:
|
|||||||
}
|
}
|
||||||
empty();
|
empty();
|
||||||
}
|
}
|
||||||
|
inline void concat(List<T> *list) { base_list::concat(list); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,7 +32,8 @@
|
|||||||
|
|
||||||
const char *join_type_str[]={ "UNKNOWN","system","const","eq_ref","ref",
|
const char *join_type_str[]={ "UNKNOWN","system","const","eq_ref","ref",
|
||||||
"MAYBE_REF","ALL","range","index","fulltext",
|
"MAYBE_REF","ALL","range","index","fulltext",
|
||||||
"ref_or_null","simple_in","index_in"
|
"ref_or_null","simple_in","index_in",
|
||||||
|
"index_merge"
|
||||||
};
|
};
|
||||||
|
|
||||||
static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array);
|
static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array);
|
||||||
@ -114,7 +115,6 @@ static int join_read_next_same_or_null(READ_RECORD *info);
|
|||||||
static COND *make_cond_for_table(COND *cond,table_map table,
|
static COND *make_cond_for_table(COND *cond,table_map table,
|
||||||
table_map used_table);
|
table_map used_table);
|
||||||
static Item* part_of_refkey(TABLE *form,Field *field);
|
static Item* part_of_refkey(TABLE *form,Field *field);
|
||||||
static uint find_shortest_key(TABLE *table, key_map usable_keys);
|
|
||||||
static bool test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,
|
static bool test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,
|
||||||
ha_rows select_limit, bool no_changes);
|
ha_rows select_limit, bool no_changes);
|
||||||
static int create_sort_index(THD *thd, JOIN *join, ORDER *order,
|
static int create_sort_index(THD *thd, JOIN *join, ORDER *order,
|
||||||
@ -5725,8 +5725,8 @@ test_if_quick_select(JOIN_TAB *tab)
|
|||||||
static int
|
static int
|
||||||
join_init_read_record(JOIN_TAB *tab)
|
join_init_read_record(JOIN_TAB *tab)
|
||||||
{
|
{
|
||||||
if (tab->select && tab->select->quick)
|
if (tab->select && tab->select->quick && tab->select->quick->reset())
|
||||||
tab->select->quick->reset();
|
return 1;
|
||||||
init_read_record(&tab->read_record, tab->join->thd, tab->table,
|
init_read_record(&tab->read_record, tab->join->thd, tab->table,
|
||||||
tab->select,1,1);
|
tab->select,1,1);
|
||||||
return (*tab->read_record.read_record)(&tab->read_record);
|
return (*tab->read_record.read_record)(&tab->read_record);
|
||||||
@ -6473,7 +6473,7 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx,
|
|||||||
return reverse;
|
return reverse;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint find_shortest_key(TABLE *table, key_map usable_keys)
|
uint find_shortest_key(TABLE *table, key_map usable_keys)
|
||||||
{
|
{
|
||||||
uint min_length= (uint) ~0;
|
uint min_length= (uint) ~0;
|
||||||
uint best= MAX_KEY;
|
uint best= MAX_KEY;
|
||||||
@ -6601,6 +6601,9 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
|
|||||||
}
|
}
|
||||||
else if (select && select->quick) // Range found by opt_range
|
else if (select && select->quick) // Range found by opt_range
|
||||||
{
|
{
|
||||||
|
/* assume results are not ordered when index merge is used */
|
||||||
|
if (select->quick->get_type() == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE)
|
||||||
|
DBUG_RETURN(0);
|
||||||
ref_key= select->quick->index;
|
ref_key= select->quick->index;
|
||||||
ref_key_parts= select->quick->used_key_parts;
|
ref_key_parts= select->quick->used_key_parts;
|
||||||
}
|
}
|
||||||
@ -6635,6 +6638,10 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
We have verified above that select->quick is not
|
||||||
|
index_merge quick select.
|
||||||
|
*/
|
||||||
select->quick->index= new_ref_key;
|
select->quick->index= new_ref_key;
|
||||||
select->quick->init();
|
select->quick->init();
|
||||||
}
|
}
|
||||||
@ -6656,10 +6663,13 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
|
|||||||
*/
|
*/
|
||||||
if (!select->quick->reverse_sorted())
|
if (!select->quick->reverse_sorted())
|
||||||
{
|
{
|
||||||
if (table->file->index_flags(ref_key) & HA_NOT_READ_PREFIX_LAST)
|
if (table->file->index_flags(ref_key) & HA_NOT_READ_PREFIX_LAST ||
|
||||||
|
(select->quick->get_type() ==
|
||||||
|
QUICK_SELECT_I::QS_TYPE_INDEX_MERGE))
|
||||||
DBUG_RETURN(0); // Use filesort
|
DBUG_RETURN(0); // Use filesort
|
||||||
|
|
||||||
// ORDER BY range_key DESC
|
// ORDER BY range_key DESC
|
||||||
QUICK_SELECT_DESC *tmp=new QUICK_SELECT_DESC(select->quick,
|
QUICK_SELECT_DESC *tmp=new QUICK_SELECT_DESC((QUICK_RANGE_SELECT*)(select->quick),
|
||||||
used_key_parts);
|
used_key_parts);
|
||||||
if (!tmp || tmp->error)
|
if (!tmp || tmp->error)
|
||||||
{
|
{
|
||||||
@ -6794,8 +6804,11 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
|
|||||||
{
|
{
|
||||||
select->quick=tab->quick;
|
select->quick=tab->quick;
|
||||||
tab->quick=0;
|
tab->quick=0;
|
||||||
/* We can only use 'Only index' if quick key is same as ref_key */
|
/*
|
||||||
if (table->key_read && (uint) tab->ref.key != select->quick->index)
|
We can only use 'Only index' if quick key is same as ref_key
|
||||||
|
and in index_merge 'Only index' cannot be used
|
||||||
|
*/
|
||||||
|
if (table->key_read && ((uint) tab->ref.key != select->quick->index))
|
||||||
{
|
{
|
||||||
table->key_read=0;
|
table->key_read=0;
|
||||||
table->file->extra(HA_EXTRA_NO_KEYREAD);
|
table->file->extra(HA_EXTRA_NO_KEYREAD);
|
||||||
@ -8598,12 +8611,15 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
|
|||||||
JOIN_TAB *tab=join->join_tab+i;
|
JOIN_TAB *tab=join->join_tab+i;
|
||||||
TABLE *table=tab->table;
|
TABLE *table=tab->table;
|
||||||
char buff[512],*buff_ptr=buff;
|
char buff[512],*buff_ptr=buff;
|
||||||
char buff1[512], buff2[512];
|
char buff1[512], buff2[512], buff3[512];
|
||||||
|
char keylen_str_buf[64];
|
||||||
char derived_name[64];
|
char derived_name[64];
|
||||||
String tmp1(buff1,sizeof(buff1),cs);
|
String tmp1(buff1,sizeof(buff1),cs);
|
||||||
String tmp2(buff2,sizeof(buff2),cs);
|
String tmp2(buff2,sizeof(buff2),cs);
|
||||||
|
String tmp3(buff3,sizeof(buff3),cs);
|
||||||
tmp1.length(0);
|
tmp1.length(0);
|
||||||
tmp2.length(0);
|
tmp2.length(0);
|
||||||
|
tmp3.length(0);
|
||||||
|
|
||||||
item_list.empty();
|
item_list.empty();
|
||||||
item_list.push_back(new Item_int((int32)
|
item_list.push_back(new Item_int((int32)
|
||||||
@ -8612,7 +8628,13 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
|
|||||||
strlen(join->select_lex->type),
|
strlen(join->select_lex->type),
|
||||||
cs));
|
cs));
|
||||||
if (tab->type == JT_ALL && tab->select && tab->select->quick)
|
if (tab->type == JT_ALL && tab->select && tab->select->quick)
|
||||||
|
{
|
||||||
|
if (tab->select->quick->get_type() ==
|
||||||
|
QUICK_SELECT_I::QS_TYPE_INDEX_MERGE)
|
||||||
|
tab->type = JT_INDEX_MERGE;
|
||||||
|
else
|
||||||
tab->type = JT_RANGE;
|
tab->type = JT_RANGE;
|
||||||
|
}
|
||||||
if (table->derived_select_number)
|
if (table->derived_select_number)
|
||||||
{
|
{
|
||||||
/* Derived table name generation */
|
/* Derived table name generation */
|
||||||
@ -8646,10 +8668,14 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
|
|||||||
if (tab->ref.key_parts)
|
if (tab->ref.key_parts)
|
||||||
{
|
{
|
||||||
KEY *key_info=table->key_info+ tab->ref.key;
|
KEY *key_info=table->key_info+ tab->ref.key;
|
||||||
|
register uint length;
|
||||||
item_list.push_back(new Item_string(key_info->name,
|
item_list.push_back(new Item_string(key_info->name,
|
||||||
strlen(key_info->name),
|
strlen(key_info->name),
|
||||||
system_charset_info));
|
system_charset_info));
|
||||||
item_list.push_back(new Item_int((int32) tab->ref.key_length));
|
length= longlong2str(tab->ref.key_length, keylen_str_buf, 10) -
|
||||||
|
keylen_str_buf;
|
||||||
|
item_list.push_back(new Item_string(keylen_str_buf, length,
|
||||||
|
system_charset_info));
|
||||||
for (store_key **ref=tab->ref.key_copy ; *ref ; ref++)
|
for (store_key **ref=tab->ref.key_copy ; *ref ; ref++)
|
||||||
{
|
{
|
||||||
if (tmp2.length())
|
if (tmp2.length())
|
||||||
@ -8661,18 +8687,60 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
|
|||||||
else if (tab->type == JT_NEXT)
|
else if (tab->type == JT_NEXT)
|
||||||
{
|
{
|
||||||
KEY *key_info=table->key_info+ tab->index;
|
KEY *key_info=table->key_info+ tab->index;
|
||||||
|
register uint length;
|
||||||
item_list.push_back(new Item_string(key_info->name,
|
item_list.push_back(new Item_string(key_info->name,
|
||||||
strlen(key_info->name),cs));
|
strlen(key_info->name),cs));
|
||||||
item_list.push_back(new Item_int((int32) key_info->key_length));
|
length= longlong2str(key_info->key_length, keylen_str_buf, 10) -
|
||||||
|
keylen_str_buf;
|
||||||
|
item_list.push_back(new Item_string(keylen_str_buf,
|
||||||
|
length,
|
||||||
|
system_charset_info));
|
||||||
item_list.push_back(item_null);
|
item_list.push_back(item_null);
|
||||||
}
|
}
|
||||||
else if (tab->select && tab->select->quick)
|
else if (tab->select && tab->select->quick)
|
||||||
|
{
|
||||||
|
if (tab->select->quick->get_type() ==
|
||||||
|
QUICK_SELECT_I::QS_TYPE_INDEX_MERGE)
|
||||||
|
{
|
||||||
|
QUICK_INDEX_MERGE_SELECT *quick_imerge=
|
||||||
|
(QUICK_INDEX_MERGE_SELECT*)tab->select->quick;
|
||||||
|
QUICK_RANGE_SELECT *quick;
|
||||||
|
|
||||||
|
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_imerge->
|
||||||
|
quick_selects);
|
||||||
|
while ((quick= it++))
|
||||||
|
{
|
||||||
|
KEY *key_info= table->key_info + quick->index;
|
||||||
|
register uint length;
|
||||||
|
if (tmp3.length())
|
||||||
|
tmp3.append(',');
|
||||||
|
|
||||||
|
tmp3.append(key_info->name);
|
||||||
|
|
||||||
|
if (tmp2.length())
|
||||||
|
tmp2.append(',');
|
||||||
|
|
||||||
|
length= longlong2str(quick->max_used_key_length, keylen_str_buf,
|
||||||
|
10) -
|
||||||
|
keylen_str_buf;
|
||||||
|
|
||||||
|
tmp2.append(keylen_str_buf, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
KEY *key_info= table->key_info + tab->select->quick->index;
|
KEY *key_info= table->key_info + tab->select->quick->index;
|
||||||
item_list.push_back(new Item_string(key_info->name,
|
register uint length;
|
||||||
strlen(key_info->name),cs));
|
tmp3.append(key_info->name);
|
||||||
item_list.push_back(new Item_int((int32) tab->select->quick->
|
|
||||||
max_used_key_length));
|
length= longlong2str(tab->select->quick->max_used_key_length,
|
||||||
|
keylen_str_buf, 10) -
|
||||||
|
keylen_str_buf;
|
||||||
|
tmp2.append(keylen_str_buf, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
item_list.push_back(new Item_string(tmp3.ptr(),tmp3.length(),cs));
|
||||||
|
item_list.push_back(new Item_string(tmp2.ptr(),tmp2.length(),cs));
|
||||||
item_list.push_back(item_null);
|
item_list.push_back(item_null);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -76,7 +76,7 @@ typedef struct st_join_cache {
|
|||||||
|
|
||||||
enum join_type { JT_UNKNOWN,JT_SYSTEM,JT_CONST,JT_EQ_REF,JT_REF,JT_MAYBE_REF,
|
enum join_type { JT_UNKNOWN,JT_SYSTEM,JT_CONST,JT_EQ_REF,JT_REF,JT_MAYBE_REF,
|
||||||
JT_ALL, JT_RANGE, JT_NEXT, JT_FT, JT_REF_OR_NULL,
|
JT_ALL, JT_RANGE, JT_NEXT, JT_FT, JT_REF_OR_NULL,
|
||||||
JT_SIMPLE_IN, JT_INDEX_IN};
|
JT_SIMPLE_IN, JT_INDEX_IN, JT_INDEX_MERGE};
|
||||||
|
|
||||||
class JOIN;
|
class JOIN;
|
||||||
|
|
||||||
@ -85,7 +85,7 @@ typedef struct st_join_table {
|
|||||||
KEYUSE *keyuse; /* pointer to first used key */
|
KEYUSE *keyuse; /* pointer to first used key */
|
||||||
SQL_SELECT *select;
|
SQL_SELECT *select;
|
||||||
COND *select_cond;
|
COND *select_cond;
|
||||||
QUICK_SELECT *quick;
|
QUICK_SELECT_I *quick;
|
||||||
Item *on_expr;
|
Item *on_expr;
|
||||||
const char *info;
|
const char *info;
|
||||||
byte *null_ref_key;
|
byte *null_ref_key;
|
||||||
@ -307,10 +307,14 @@ void copy_fields(TMP_TABLE_PARAM *param);
|
|||||||
void copy_funcs(Item **func_ptr);
|
void copy_funcs(Item **func_ptr);
|
||||||
bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
|
bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
|
||||||
int error, bool ignore_last_dupp_error);
|
int error, bool ignore_last_dupp_error);
|
||||||
|
uint find_shortest_key(TABLE *table, key_map usable_keys);
|
||||||
|
|
||||||
/* functions from opt_sum.cc */
|
/* functions from opt_sum.cc */
|
||||||
int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds);
|
int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds);
|
||||||
|
|
||||||
|
/* from sql_delete.cc, used by opt_range.cc */
|
||||||
|
extern "C" int refposcmp2(void* arg, const void *a,const void *b);
|
||||||
|
|
||||||
/* class to copying an field/item to a key struct */
|
/* class to copying an field/item to a key struct */
|
||||||
|
|
||||||
class store_key :public Sql_alloc
|
class store_key :public Sql_alloc
|
||||||
|
@ -179,9 +179,39 @@ TEST_join(JOIN *join)
|
|||||||
" quick select checked for each record (keys: %d)\n",
|
" quick select checked for each record (keys: %d)\n",
|
||||||
(int) tab->select->quick_keys);
|
(int) tab->select->quick_keys);
|
||||||
else if (tab->select->quick)
|
else if (tab->select->quick)
|
||||||
fprintf(DBUG_FILE," quick select used on key %s, length: %d\n",
|
{
|
||||||
|
int quick_type= tab->select->quick->get_type();
|
||||||
|
if ((quick_type == QUICK_SELECT_I::QS_TYPE_RANGE) ||
|
||||||
|
(quick_type == QUICK_SELECT_I::QS_TYPE_RANGE_DESC))
|
||||||
|
{
|
||||||
|
fprintf(DBUG_FILE,
|
||||||
|
" quick select used on key %s, length: %d\n",
|
||||||
form->key_info[tab->select->quick->index].name,
|
form->key_info[tab->select->quick->index].name,
|
||||||
tab->select->quick->max_used_key_length);
|
tab->select->quick->max_used_key_length);
|
||||||
|
}
|
||||||
|
else if (quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE)
|
||||||
|
{
|
||||||
|
QUICK_INDEX_MERGE_SELECT *quick_imerge=
|
||||||
|
(QUICK_INDEX_MERGE_SELECT*)tab->select->quick;
|
||||||
|
QUICK_RANGE_SELECT *quick;
|
||||||
|
fprintf(DBUG_FILE,
|
||||||
|
" index_merge quick select used\n");
|
||||||
|
|
||||||
|
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_imerge->quick_selects);
|
||||||
|
while ((quick = it++))
|
||||||
|
{
|
||||||
|
fprintf(DBUG_FILE,
|
||||||
|
" range quick select: key %s, length: %d\n",
|
||||||
|
form->key_info[quick->index].name,
|
||||||
|
quick->max_used_key_length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(DBUG_FILE,
|
||||||
|
" quick select of unknown nature used\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
VOID(fputs(" select used\n",DBUG_FILE));
|
VOID(fputs(" select used\n",DBUG_FILE));
|
||||||
}
|
}
|
||||||
|
@ -117,6 +117,7 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result,
|
|||||||
{
|
{
|
||||||
SELECT_LEX *lex_select_save= thd->lex.current_select;
|
SELECT_LEX *lex_select_save= thd->lex.current_select;
|
||||||
SELECT_LEX *select_cursor;
|
SELECT_LEX *select_cursor;
|
||||||
|
SELECT_LEX *sl;
|
||||||
DBUG_ENTER("st_select_lex_unit::prepare");
|
DBUG_ENTER("st_select_lex_unit::prepare");
|
||||||
|
|
||||||
if (prepared)
|
if (prepared)
|
||||||
@ -185,7 +186,7 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result,
|
|||||||
union_result->not_describe=1;
|
union_result->not_describe=1;
|
||||||
union_result->tmp_table_param=tmp_table_param;
|
union_result->tmp_table_param=tmp_table_param;
|
||||||
|
|
||||||
for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select())
|
for (sl= select_cursor; sl; sl= sl->next_select())
|
||||||
{
|
{
|
||||||
JOIN *join= new JOIN(thd, sl->item_list,
|
JOIN *join= new JOIN(thd, sl->item_list,
|
||||||
sl->options | thd->options | SELECT_NO_UNLOCK,
|
sl->options | thd->options | SELECT_NO_UNLOCK,
|
||||||
|
@ -171,10 +171,18 @@ int mysql_update(THD *thd,
|
|||||||
init_ftfuncs(thd, &thd->lex.select_lex, 1);
|
init_ftfuncs(thd, &thd->lex.select_lex, 1);
|
||||||
/* Check if we are modifying a key that we are used to search with */
|
/* Check if we are modifying a key that we are used to search with */
|
||||||
if (select && select->quick)
|
if (select && select->quick)
|
||||||
|
{
|
||||||
|
if (select->quick->get_type() != QUICK_SELECT_I::QS_TYPE_INDEX_MERGE)
|
||||||
|
{
|
||||||
|
used_index= select->quick->index;
|
||||||
used_key_is_modified= (!select->quick->unique_key_range() &&
|
used_key_is_modified= (!select->quick->unique_key_range() &&
|
||||||
check_if_key_used(table,
|
check_if_key_used(table,used_index,fields));
|
||||||
(used_index=select->quick->index),
|
}
|
||||||
fields));
|
else
|
||||||
|
{
|
||||||
|
used_key_is_modified= true;
|
||||||
|
}
|
||||||
|
}
|
||||||
else if ((used_index=table->file->key_used_on_scan) < MAX_KEY)
|
else if ((used_index=table->file->key_used_on_scan) < MAX_KEY)
|
||||||
used_key_is_modified=check_if_key_used(table, used_index, fields);
|
used_key_is_modified=check_if_key_used(table, used_index, fields);
|
||||||
else
|
else
|
||||||
@ -688,8 +696,26 @@ static bool safe_update_on_fly(JOIN_TAB *join_tab, List<Item> *fields)
|
|||||||
case JT_ALL:
|
case JT_ALL:
|
||||||
/* If range search on index */
|
/* If range search on index */
|
||||||
if (join_tab->quick)
|
if (join_tab->quick)
|
||||||
return !check_if_key_used(table, join_tab->quick->index,
|
{
|
||||||
*fields);
|
if (join_tab->quick->get_type() != QUICK_SELECT_I::QS_TYPE_INDEX_MERGE)
|
||||||
|
{
|
||||||
|
return !check_if_key_used(table,join_tab->quick->index,*fields);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QUICK_INDEX_MERGE_SELECT *qsel_imerge=
|
||||||
|
(QUICK_INDEX_MERGE_SELECT*)(join_tab->quick);
|
||||||
|
List_iterator_fast<QUICK_RANGE_SELECT> it(qsel_imerge->quick_selects);
|
||||||
|
QUICK_RANGE_SELECT *quick;
|
||||||
|
while ((quick= it++))
|
||||||
|
{
|
||||||
|
if (check_if_key_used(table, quick->index, *fields))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* If scanning in clustered key */
|
/* If scanning in clustered key */
|
||||||
if ((table->file->table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) &&
|
if ((table->file->table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) &&
|
||||||
table->primary_key < MAX_KEY)
|
table->primary_key < MAX_KEY)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user