Commit e0999cdf authored by Sergey Petrunya's avatar Sergey Petrunya

DS-MRR support improvements (MWL#123, MWL#124, MWL#125)

- Lots of TODO comments
- add mrr_sort_keys flag to @@optimizer_switch
- [from Igor] SQL layer part passes HA_MRR_MATERIALIZED_KEYS flag
- Don't call rnd_pos() many times in a row if sorted rowid buffer
  has the same rowid value for multiple consequive (rowid, range_id) pairs.
parent e1006e9e
...@@ -4,19 +4,19 @@ ...@@ -4,19 +4,19 @@
# #
select @@optimizer_switch; select @@optimizer_switch;
@@optimizer_switch @@optimizer_switch
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr_sort_keys=on
set optimizer_switch='index_merge=off,index_merge_union=off'; set optimizer_switch='index_merge=off,index_merge_union=off';
select @@optimizer_switch; select @@optimizer_switch;
@@optimizer_switch @@optimizer_switch
index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr_sort_keys=on
set optimizer_switch='index_merge_union=on'; set optimizer_switch='index_merge_union=on';
select @@optimizer_switch; select @@optimizer_switch;
@@optimizer_switch @@optimizer_switch
index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr_sort_keys=on
set optimizer_switch='default,index_merge_sort_union=off'; set optimizer_switch='default,index_merge_sort_union=off';
select @@optimizer_switch; select @@optimizer_switch;
@@optimizer_switch @@optimizer_switch
index_merge=on,index_merge_union=on,index_merge_sort_union=off,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on index_merge=on,index_merge_union=on,index_merge_sort_union=off,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr_sort_keys=on
set optimizer_switch=4; set optimizer_switch=4;
ERROR 42000: Variable 'optimizer_switch' can't be set to the value of '4' ERROR 42000: Variable 'optimizer_switch' can't be set to the value of '4'
set optimizer_switch=NULL; set optimizer_switch=NULL;
...@@ -43,57 +43,57 @@ set optimizer_switch=default; ...@@ -43,57 +43,57 @@ set optimizer_switch=default;
set optimizer_switch='index_merge=off,index_merge_union=off,default'; set optimizer_switch='index_merge=off,index_merge_union=off,default';
select @@optimizer_switch; select @@optimizer_switch;
@@optimizer_switch @@optimizer_switch
index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr_sort_keys=on
set optimizer_switch=default; set optimizer_switch=default;
select @@global.optimizer_switch; select @@global.optimizer_switch;
@@global.optimizer_switch @@global.optimizer_switch
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr_sort_keys=on
set @@global.optimizer_switch=default; set @@global.optimizer_switch=default;
select @@global.optimizer_switch; select @@global.optimizer_switch;
@@global.optimizer_switch @@global.optimizer_switch
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr_sort_keys=on
# #
# Check index_merge's @@optimizer_switch flags # Check index_merge's @@optimizer_switch flags
# #
select @@optimizer_switch; select @@optimizer_switch;
@@optimizer_switch @@optimizer_switch
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr_sort_keys=on
BUG#37120 optimizer_switch allowable values not according to specification BUG#37120 optimizer_switch allowable values not according to specification
select @@optimizer_switch; select @@optimizer_switch;
@@optimizer_switch @@optimizer_switch
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr_sort_keys=on
set optimizer_switch='default,materialization=off'; set optimizer_switch='default,materialization=off';
select @@optimizer_switch; select @@optimizer_switch;
@@optimizer_switch @@optimizer_switch
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=off,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=off,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr_sort_keys=on
set optimizer_switch='default,semijoin=off'; set optimizer_switch='default,semijoin=off';
select @@optimizer_switch; select @@optimizer_switch;
@@optimizer_switch @@optimizer_switch
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr_sort_keys=on
set optimizer_switch='default,loosescan=off'; set optimizer_switch='default,loosescan=off';
select @@optimizer_switch; select @@optimizer_switch;
@@optimizer_switch @@optimizer_switch
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=off,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=off,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr_sort_keys=on
set optimizer_switch='default,semijoin=off,materialization=off'; set optimizer_switch='default,semijoin=off,materialization=off';
select @@optimizer_switch; select @@optimizer_switch;
@@optimizer_switch @@optimizer_switch
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=off,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=off,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr_sort_keys=on
set optimizer_switch='default,materialization=off,semijoin=off'; set optimizer_switch='default,materialization=off,semijoin=off';
select @@optimizer_switch; select @@optimizer_switch;
@@optimizer_switch @@optimizer_switch
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=off,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=off,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr_sort_keys=on
set optimizer_switch='default,semijoin=off,materialization=off,loosescan=off'; set optimizer_switch='default,semijoin=off,materialization=off,loosescan=off';
select @@optimizer_switch; select @@optimizer_switch;
@@optimizer_switch @@optimizer_switch
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=off,materialization=off,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=off,materialization=off,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr_sort_keys=on
set optimizer_switch='default,semijoin=off,loosescan=off'; set optimizer_switch='default,semijoin=off,loosescan=off';
select @@optimizer_switch; select @@optimizer_switch;
@@optimizer_switch @@optimizer_switch
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=off,materialization=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=off,materialization=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr_sort_keys=on
set optimizer_switch='default,materialization=off,loosescan=off'; set optimizer_switch='default,materialization=off,loosescan=off';
select @@optimizer_switch; select @@optimizer_switch;
@@optimizer_switch @@optimizer_switch
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=off,materialization=off,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=off,materialization=off,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr_sort_keys=on
set optimizer_switch=default; set optimizer_switch=default;
...@@ -1322,6 +1322,12 @@ void get_sweep_read_cost(TABLE *table, ha_rows nrows, bool interrupted, ...@@ -1322,6 +1322,12 @@ void get_sweep_read_cost(TABLE *table, ha_rows nrows, bool interrupted,
*/ */
#define HA_MRR_NO_NULL_ENDPOINTS 128 #define HA_MRR_NO_NULL_ENDPOINTS 128
/*
The MRR user has materialized range keys somewhere in the user's buffer.
This can be used for optimization of the procedure that sorts these keys
since in this case key values don't have to be copied into the MRR buffer.
*/
#define HA_MRR_MATERIALIZED_KEYS 256
/* /*
......
...@@ -327,24 +327,62 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs, ...@@ -327,24 +327,62 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
mode, buf); mode, buf);
DBUG_RETURN(retval); DBUG_RETURN(retval);
} }
mrr_buf= buf->buffer; use_default_impl= FALSE;
is_mrr_assoc= !test(mode & HA_MRR_NO_ASSOCIATION); is_mrr_assoc= !test(mode & HA_MRR_NO_ASSOCIATION);
// psergey2: split the buffer:
/*
psergey2-note: we can't split the buffer here because we don't know how key
length. we'll only be able to do it when we've got the first range.
if ((mrr_flags & HA_MRR_SINGLE_POINT) &&
optimizer_flag(thd, OPTIMIZER_SWITCH_MRR_SORT_KEYS))
{
do_sort_keys= TRUE; // will use key buffer to sort keys;
bool use_key_pointers= test(mrr_flags & HA_MRR_MATERIALIZED_KEYS);
}
do_rowid_fetch= FALSE;
if (!doing_cpk_scan && !index_only_read)
{
do_rowid_fetch= TRUE; //will use rowid buffer to store/sort rowids, etc
}
if (do_sort_keys && do_rowid_fetch)
{
split buffer space proportionally
}
else
{
// give all space to one buffer
if (do_sort_keys)
{
//sort_buffer_start= ...;
}
else
{
DBUG_ASSERT(do_rowid_fetch);
//rowid_buffer_start= ...;
}
}
*/
mrr_buf= buf->buffer;
mrr_buf_end= buf->buffer_end;
if (is_mrr_assoc) if (is_mrr_assoc)
status_var_increment(table->in_use->status_var.ha_multi_range_read_init_count); status_var_increment(table->in_use->status_var.ha_multi_range_read_init_count);
mrr_buf_end= buf->buffer_end;
if ((doing_cpk_scan= check_cpk_scan(h->active_index, mode))) if ((doing_cpk_scan= check_cpk_scan(h->active_index, mode)))
{ {
/* It's a DS-MRR/CPK scan */ /* It's a DS-MRR/CPK scan */
cpk_tuple_length= 0; /* dummy value telling it needs to be inited */ cpk_tuple_length= 0; /* dummy value telling it needs to be inited */
cpk_have_range= FALSE; cpk_have_range= FALSE;
use_default_impl= FALSE;
h->mrr_iter= seq_funcs->init(seq_init_param, n_ranges, mode); h->mrr_iter= seq_funcs->init(seq_init_param, n_ranges, mode);
h->mrr_funcs= *seq_funcs; h->mrr_funcs= *seq_funcs;
dsmrr_fill_buffer_cpk(); dsmrr_fill_key_buffer();
if (dsmrr_eof) if (dsmrr_eof)
buf->end_of_used_area= mrr_buf_last; buf->end_of_used_area= mrr_buf_last;
DBUG_RETURN(0); /* nothing could go wrong while filling the buffer */ DBUG_RETURN(0); /* nothing could go wrong while filling the buffer */
...@@ -355,6 +393,11 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs, ...@@ -355,6 +393,11 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
mrr_buf_last= mrr_buf + ((mrr_buf_end - mrr_buf)/ elem_size)* elem_size; mrr_buf_last= mrr_buf + ((mrr_buf_end - mrr_buf)/ elem_size)* elem_size;
mrr_buf_end= mrr_buf_last; mrr_buf_end= mrr_buf_last;
/*
psergey2: this is only needed when
- doing a rowid-to-row scan
- the buffer wasn't exhausted on the first pass.
*/
/* /*
There can be two cases: There can be two cases:
- This is the first call since index_init(), h2==NULL - This is the first call since index_init(), h2==NULL
...@@ -365,7 +408,7 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs, ...@@ -365,7 +408,7 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
*/ */
if (!h2) if (!h2)
{ {
/* Create a separate handler object to do rndpos() calls. */ /* Create a separate handler object to do rnd_pos() calls. */
THD *thd= current_thd; THD *thd= current_thd;
/* /*
::clone() takes up a lot of stack, especially on 64 bit platforms. ::clone() takes up a lot of stack, especially on 64 bit platforms.
...@@ -376,7 +419,7 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs, ...@@ -376,7 +419,7 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
DBUG_ASSERT(h->active_index != MAX_KEY); DBUG_ASSERT(h->active_index != MAX_KEY);
uint mrr_keyno= h->active_index; uint mrr_keyno= h->active_index;
/* Create a separate handler object to do rndpos() calls. */ /* Create a separate handler object to do rnd_pos() calls. */
if (!(new_h2= h->clone(thd->mem_root)) || if (!(new_h2= h->clone(thd->mem_root)) ||
new_h2->ha_external_lock(thd, F_RDLCK)) new_h2->ha_external_lock(thd, F_RDLCK))
{ {
...@@ -397,6 +440,7 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs, ...@@ -397,6 +440,7 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
goto error; goto error;
} }
use_default_impl= FALSE;
h2= new_h2; /* Ok, now can put it into h2 */ h2= new_h2; /* Ok, now can put it into h2 */
table->prepare_for_position(); table->prepare_for_position();
h2->extra(HA_EXTRA_KEYREAD); h2->extra(HA_EXTRA_KEYREAD);
...@@ -404,7 +448,6 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs, ...@@ -404,7 +448,6 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
if (h2->ha_index_init(mrr_keyno, FALSE)) if (h2->ha_index_init(mrr_keyno, FALSE))
goto error; goto error;
use_default_impl= FALSE;
if (pushed_cond) if (pushed_cond)
h2->idx_cond_push(mrr_keyno, pushed_cond); h2->idx_cond_push(mrr_keyno, pushed_cond);
} }
...@@ -422,14 +465,13 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs, ...@@ -422,14 +465,13 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
h2= NULL; h2= NULL;
int res= (h->inited == handler::INDEX && h->ha_index_end()); int res= (h->inited == handler::INDEX && h->ha_index_end());
h2= save_h2; h2= save_h2;
use_default_impl= FALSE;
if (res) if (res)
goto error; goto error;
} }
if (h2->handler::multi_range_read_init(seq_funcs, seq_init_param, n_ranges, if (h2->handler::multi_range_read_init(seq_funcs, seq_init_param, n_ranges,
mode, buf) || mode, buf) ||
dsmrr_fill_buffer()) dsmrr_fill_rowid_buffer())
{ {
goto error; goto error;
} }
...@@ -449,7 +491,6 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs, ...@@ -449,7 +491,6 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
(h->ha_rnd_init(FALSE)))) (h->ha_rnd_init(FALSE))))
goto error; goto error;
use_default_impl= FALSE;
h->mrr_funcs= *seq_funcs; h->mrr_funcs= *seq_funcs;
DBUG_RETURN(0); DBUG_RETURN(0);
...@@ -497,6 +538,9 @@ static int rowid_cmp(void *h, uchar *a, uchar *b) ...@@ -497,6 +538,9 @@ static int rowid_cmp(void *h, uchar *a, uchar *b)
dsmrr_eof is set to indicate whether we've exhausted the list of ranges we're dsmrr_eof is set to indicate whether we've exhausted the list of ranges we're
scanning. scanning.
psergey2: this func will 'fill the rowid buffer'. If filling the rowid buffer
requires that key buffer is filled/sorted first, will do that, too.
@param h Table handler @param h Table handler
...@@ -505,13 +549,27 @@ static int rowid_cmp(void *h, uchar *a, uchar *b) ...@@ -505,13 +549,27 @@ static int rowid_cmp(void *h, uchar *a, uchar *b)
@retval other Error @retval other Error
*/ */
int DsMrr_impl::dsmrr_fill_buffer() int DsMrr_impl::dsmrr_fill_rowid_buffer()
{ {
char *range_info; char *range_info;
int res; int res;
DBUG_ENTER("DsMrr_impl::dsmrr_fill_buffer"); DBUG_ENTER("DsMrr_impl::dsmrr_fill_rowid_buffer");
mrr_buf_cur= mrr_buf; mrr_buf_cur= mrr_buf;
mrr_buf_next_identical= mrr_buf_cur;
/*
psergey2-todo:
- call here fill/sort key buffer, if needed.
psergey2-todo: then, get keys either from
- multi_range_read_next()
- sorted key buffer
psergey2-todo: if we're traversing an ordered key sequence,
check if next keys are the same as previous.
(note that it's easy as ordered sequence allows forward/backward
navigation so we don't need to buffer things)
*/
while ((mrr_buf_cur < mrr_buf_end) && while ((mrr_buf_cur < mrr_buf_end) &&
!(res= h2->handler::multi_range_read_next(&range_info))) !(res= h2->handler::multi_range_read_next(&range_info)))
{ {
...@@ -520,6 +578,7 @@ int DsMrr_impl::dsmrr_fill_buffer() ...@@ -520,6 +578,7 @@ int DsMrr_impl::dsmrr_fill_buffer()
h2->mrr_funcs.skip_index_tuple(h2->mrr_iter, curr_range->ptr)) h2->mrr_funcs.skip_index_tuple(h2->mrr_iter, curr_range->ptr))
continue; continue;
/* Put rowid, or {rowid, range_id} pair into the buffer */ /* Put rowid, or {rowid, range_id} pair into the buffer */
h2->position(table->record[0]); h2->position(table->record[0]);
memcpy(mrr_buf_cur, h2->ref, h2->ref_length); memcpy(mrr_buf_cur, h2->ref, h2->ref_length);
...@@ -579,20 +638,26 @@ int DsMrr_impl::key_tuple_cmp(void* arg, uchar* key1, uchar* key2) ...@@ -579,20 +638,26 @@ int DsMrr_impl::key_tuple_cmp(void* arg, uchar* key1, uchar* key2)
DS-MRR/CPK: Fill the buffer with (lookup_tuple, range_id) pairs and sort DS-MRR/CPK: Fill the buffer with (lookup_tuple, range_id) pairs and sort
SYNOPSIS SYNOPSIS
DsMrr_impl::dsmrr_fill_buffer_cpk() DsMrr_impl::dsmrr_fill_key_buffer()
DESCRIPTION DESCRIPTION
DS-MRR/CPK: Fill the buffer with (lookup_tuple, range_id) pairs and sort DS-MRR/CPK: Fill the buffer with (lookup_tuple, range_id) pairs and sort
dsmrr_eof is set to indicate whether we've exhausted the list of ranges dsmrr_eof is set to indicate whether we've exhausted the list of ranges
we're scanning. we're scanning.
psergey2-q: can this be used for filling/sorting key buffer in general case?
a: yes.
qq: can we push sequence iteration init down into here?
*/ */
void DsMrr_impl::dsmrr_fill_buffer_cpk() void DsMrr_impl::dsmrr_fill_key_buffer()
{ {
//psergey2: here, no identicals detection is necessary since we always scan
// the unordered sequence.
int res; int res;
KEY_MULTI_RANGE cur_range; KEY_MULTI_RANGE cur_range;
DBUG_ENTER("DsMrr_impl::dsmrr_fill_buffer_cpk"); DBUG_ENTER("DsMrr_impl::dsmrr_fill_key_buffer");
mrr_buf_cur= mrr_buf; mrr_buf_cur= mrr_buf;
while ((mrr_buf_cur < mrr_buf_end) && while ((mrr_buf_cur < mrr_buf_end) &&
...@@ -611,6 +676,8 @@ void DsMrr_impl::dsmrr_fill_buffer_cpk() ...@@ -611,6 +676,8 @@ void DsMrr_impl::dsmrr_fill_buffer_cpk()
mrr_buf_end= mrr_buf_last; mrr_buf_end= mrr_buf_last;
} }
//psergey2: if keys are materialized, store pointers, not copy keys
/* Put key, or {key, range_id} pair into the buffer */ /* Put key, or {key, range_id} pair into the buffer */
memcpy(mrr_buf_cur, cur_range.start_key.key, cpk_tuple_length); memcpy(mrr_buf_cur, cur_range.start_key.key, cpk_tuple_length);
mrr_buf_cur += cpk_tuple_length; mrr_buf_cur += cpk_tuple_length;
...@@ -648,12 +715,14 @@ void DsMrr_impl::dsmrr_fill_buffer_cpk() ...@@ -648,12 +715,14 @@ void DsMrr_impl::dsmrr_fill_buffer_cpk()
This is similar to DsMrr_impl::dsmrr_next(), the differences are that This is similar to DsMrr_impl::dsmrr_next(), the differences are that
- we get records with index_read(), not with rnd_pos() - we get records with index_read(), not with rnd_pos()
- we may get multiple records for one key (=element of the buffer) - we may get multiple records for one key (=element of the buffer)
- unlike dsmrr_fill_buffer(), dsmrr_fill_buffer_cpk() never fails. - unlike dsmrr_fill_rowid_buffer(), dsmrr_fill_key_buffer() never fails.
RETURN RETURN
0 OK, next record was successfully read 0 OK, next record was successfully read
HA_ERR_END_OF_FILE End of records HA_ERR_END_OF_FILE End of records
Other Some other error Other Some other error
psergey2-todo: this should detect identical keys.
*/ */
int DsMrr_impl::dsmrr_next_cpk(char **range_info) int DsMrr_impl::dsmrr_next_cpk(char **range_info)
...@@ -697,7 +766,7 @@ int DsMrr_impl::dsmrr_next_cpk(char **range_info) ...@@ -697,7 +766,7 @@ int DsMrr_impl::dsmrr_next_cpk(char **range_info)
res= HA_ERR_END_OF_FILE; res= HA_ERR_END_OF_FILE;
goto end; goto end;
} }
dsmrr_fill_buffer_cpk(); dsmrr_fill_key_buffer();
} }
if (mrr_buf_cur == mrr_buf_last) if (mrr_buf_cur == mrr_buf_last)
{ {
...@@ -758,6 +827,9 @@ end: ...@@ -758,6 +827,9 @@ end:
/** /**
DS-MRR implementation: multi_range_read_next() function DS-MRR implementation: multi_range_read_next() function
psergey2-todo: put identical rowid detection code here
it should always work because rowid sequences are always sorted
*/ */
int DsMrr_impl::dsmrr_next(char **range_info) int DsMrr_impl::dsmrr_next(char **range_info)
...@@ -772,6 +844,23 @@ int DsMrr_impl::dsmrr_next(char **range_info) ...@@ -772,6 +844,23 @@ int DsMrr_impl::dsmrr_next(char **range_info)
if (doing_cpk_scan) if (doing_cpk_scan)
return dsmrr_next_cpk(range_info); return dsmrr_next_cpk(range_info);
if (mrr_buf_next_identical != mrr_buf_cur)
{
/*
There are multiple rowids. Return the record again, now with different
range_id
*/
do
{
if (is_mrr_assoc)
memcpy(range_info, mrr_buf_next_identical + h->ref_length, sizeof(uchar*));
} while (!h2->mrr_funcs.skip_record ||
!h2->mrr_funcs.skip_record(h2->mrr_iter, (char *) range_info, rowid));
mrr_buf_next_identical += h->ref_length + sizeof(void*) * test(is_mrr_assoc);
return 0;
}
do do
{ {
if (mrr_buf_cur == mrr_buf_last) if (mrr_buf_cur == mrr_buf_last)
...@@ -781,7 +870,7 @@ int DsMrr_impl::dsmrr_next(char **range_info) ...@@ -781,7 +870,7 @@ int DsMrr_impl::dsmrr_next(char **range_info)
res= HA_ERR_END_OF_FILE; res= HA_ERR_END_OF_FILE;
goto end; goto end;
} }
res= dsmrr_fill_buffer(); res= dsmrr_fill_rowid_buffer();
if (res) if (res)
goto end; goto end;
} }
...@@ -796,13 +885,34 @@ int DsMrr_impl::dsmrr_next(char **range_info) ...@@ -796,13 +885,34 @@ int DsMrr_impl::dsmrr_next(char **range_info)
if (is_mrr_assoc) if (is_mrr_assoc)
memcpy(&cur_range_info, mrr_buf_cur + h->ref_length, sizeof(uchar**)); memcpy(&cur_range_info, mrr_buf_cur + h->ref_length, sizeof(uchar**));
size_t element_size= h->ref_length + sizeof(void*) * test(is_mrr_assoc);
mrr_buf_cur += element_size;
mrr_buf_next_identical= mrr_buf_cur;
mrr_buf_cur += h->ref_length + sizeof(void*) * test(is_mrr_assoc);
if (h2->mrr_funcs.skip_record && if (h2->mrr_funcs.skip_record &&
h2->mrr_funcs.skip_record(h2->mrr_iter, (char *) cur_range_info, rowid)) h2->mrr_funcs.skip_record(h2->mrr_iter, (char *) cur_range_info, rowid))
continue; continue;
res= h->ha_rnd_pos(table->record[0], rowid); res= h->ha_rnd_pos(table->record[0], rowid);
if (res == HA_ERR_RECORD_DELETED)
continue;
if (0)//(!res)
{
/*
Note: this implies that SQL layer doesn't touch table->record[0]
between calls.
*/
uchar *current_el= mrr_buf_cur - element_size;
while (mrr_buf_cur != mrr_buf_last &&
!h2->cmp_ref(current_el, mrr_buf_cur))
{
mrr_buf_cur += element_size;
}
}
break; break;
} while (true); } while (true);
if (is_mrr_assoc) if (is_mrr_assoc)
...@@ -986,7 +1096,7 @@ bool DsMrr_impl::choose_mrr_impl(uint keyno, ha_rows rows, uint *flags, ...@@ -986,7 +1096,7 @@ bool DsMrr_impl::choose_mrr_impl(uint keyno, ha_rows rows, uint *flags,
*flags |= HA_MRR_USE_DEFAULT_IMPL; *flags |= HA_MRR_USE_DEFAULT_IMPL;
return TRUE; return TRUE;
} }
uint add_len= table->key_info[keyno].key_length + h->ref_length; uint add_len= table->key_info[keyno].key_length + h->ref_length;
*bufsz -= add_len; *bufsz -= add_len;
if (get_disk_sweep_mrr_cost(keyno, rows, *flags, bufsz, &dsmrr_cost)) if (get_disk_sweep_mrr_cost(keyno, rows, *flags, bufsz, &dsmrr_cost))
...@@ -1010,6 +1120,10 @@ bool DsMrr_impl::choose_mrr_impl(uint keyno, ha_rows rows, uint *flags, ...@@ -1010,6 +1120,10 @@ bool DsMrr_impl::choose_mrr_impl(uint keyno, ha_rows rows, uint *flags,
*flags &= ~HA_MRR_SORTED; /* We will return unordered output */ *flags &= ~HA_MRR_SORTED; /* We will return unordered output */
*cost= dsmrr_cost; *cost= dsmrr_cost;
res= FALSE; res= FALSE;
if ((*flags & HA_MRR_SINGLE_POINT) &&
optimizer_flag(thd, OPTIMIZER_SWITCH_MRR_SORT_KEYS))
*flags |= HA_MRR_MATERIALIZED_KEYS;
} }
else else
{ {
......
...@@ -114,6 +114,8 @@ private: ...@@ -114,6 +114,8 @@ private:
uchar *mrr_buf_last; /* When reading: end of used buffer space */ uchar *mrr_buf_last; /* When reading: end of used buffer space */
uchar *mrr_buf_end; /* End of the buffer */ uchar *mrr_buf_end; /* End of the buffer */
uchar *mrr_buf_next_identical;
bool dsmrr_eof; /* TRUE <=> We have reached EOF when reading index tuples */ bool dsmrr_eof; /* TRUE <=> We have reached EOF when reading index tuples */
/* TRUE <=> need range association, buffer holds {rowid, range_id} pairs */ /* TRUE <=> need range association, buffer holds {rowid, range_id} pairs */
...@@ -143,8 +145,8 @@ private: ...@@ -143,8 +145,8 @@ private:
uint *buffer_size, COST_VECT *cost); uint *buffer_size, COST_VECT *cost);
bool check_cpk_scan(uint keyno, uint mrr_flags); bool check_cpk_scan(uint keyno, uint mrr_flags);
static int key_tuple_cmp(void* arg, uchar* key1, uchar* key2); static int key_tuple_cmp(void* arg, uchar* key1, uchar* key2);
int dsmrr_fill_buffer(); int dsmrr_fill_rowid_buffer();
void dsmrr_fill_buffer_cpk(); void dsmrr_fill_key_buffer();
int dsmrr_next_cpk(char **range_info); int dsmrr_next_cpk(char **range_info);
}; };
...@@ -571,12 +571,13 @@ protected: ...@@ -571,12 +571,13 @@ protected:
#define OPTIMIZER_SWITCH_PARTIAL_MATCH_ROWID_MERGE 512 #define OPTIMIZER_SWITCH_PARTIAL_MATCH_ROWID_MERGE 512
#define OPTIMIZER_SWITCH_PARTIAL_MATCH_TABLE_SCAN 1024 #define OPTIMIZER_SWITCH_PARTIAL_MATCH_TABLE_SCAN 1024
#define OPTIMIZER_SWITCH_SUBQUERY_CACHE (1<<11) #define OPTIMIZER_SWITCH_SUBQUERY_CACHE (1<<11)
#define OPTIMIZER_SWITCH_MRR_SORT_KEYS (1<<12)
#ifdef DBUG_OFF #ifdef DBUG_OFF
# define OPTIMIZER_SWITCH_LAST (1<<12)
#else
# define OPTIMIZER_SWITCH_TABLE_ELIMINATION (1<<12)
# define OPTIMIZER_SWITCH_LAST (1<<13) # define OPTIMIZER_SWITCH_LAST (1<<13)
#else
# define OPTIMIZER_SWITCH_TABLE_ELIMINATION (1<<13)
# define OPTIMIZER_SWITCH_LAST (1<<14)
#endif #endif
#ifdef DBUG_OFF #ifdef DBUG_OFF
...@@ -592,7 +593,8 @@ protected: ...@@ -592,7 +593,8 @@ protected:
OPTIMIZER_SWITCH_SEMIJOIN | \ OPTIMIZER_SWITCH_SEMIJOIN | \
OPTIMIZER_SWITCH_PARTIAL_MATCH_ROWID_MERGE|\ OPTIMIZER_SWITCH_PARTIAL_MATCH_ROWID_MERGE|\
OPTIMIZER_SWITCH_PARTIAL_MATCH_TABLE_SCAN|\ OPTIMIZER_SWITCH_PARTIAL_MATCH_TABLE_SCAN|\
OPTIMIZER_SWITCH_SUBQUERY_CACHE) OPTIMIZER_SWITCH_SUBQUERY_CACHE|\
OPTIMIZER_SWITCH_MRR_SORT_KEYS)
#else #else
# define OPTIMIZER_SWITCH_DEFAULT (OPTIMIZER_SWITCH_INDEX_MERGE | \ # define OPTIMIZER_SWITCH_DEFAULT (OPTIMIZER_SWITCH_INDEX_MERGE | \
OPTIMIZER_SWITCH_INDEX_MERGE_UNION | \ OPTIMIZER_SWITCH_INDEX_MERGE_UNION | \
...@@ -606,7 +608,8 @@ protected: ...@@ -606,7 +608,8 @@ protected:
OPTIMIZER_SWITCH_SEMIJOIN | \ OPTIMIZER_SWITCH_SEMIJOIN | \
OPTIMIZER_SWITCH_PARTIAL_MATCH_ROWID_MERGE|\ OPTIMIZER_SWITCH_PARTIAL_MATCH_ROWID_MERGE|\
OPTIMIZER_SWITCH_PARTIAL_MATCH_TABLE_SCAN|\ OPTIMIZER_SWITCH_PARTIAL_MATCH_TABLE_SCAN|\
OPTIMIZER_SWITCH_SUBQUERY_CACHE) OPTIMIZER_SWITCH_SUBQUERY_CACHE|\
OPTIMIZER_SWITCH_MRR_SORT_KEYS)
#endif #endif
/* /*
......
...@@ -308,6 +308,7 @@ static const char *optimizer_switch_names[]= ...@@ -308,6 +308,7 @@ static const char *optimizer_switch_names[]=
"partial_match_rowid_merge", "partial_match_rowid_merge",
"partial_match_table_scan", "partial_match_table_scan",
"subquery_cache", "subquery_cache",
"mrr_sort_keys",
#ifndef DBUG_OFF #ifndef DBUG_OFF
"table_elimination", "table_elimination",
#endif #endif
...@@ -329,6 +330,7 @@ static const unsigned int optimizer_switch_names_len[]= ...@@ -329,6 +330,7 @@ static const unsigned int optimizer_switch_names_len[]=
sizeof("partial_match_rowid_merge") - 1, sizeof("partial_match_rowid_merge") - 1,
sizeof("partial_match_table_scan") - 1, sizeof("partial_match_table_scan") - 1,
sizeof("subquery_cache") - 1, sizeof("subquery_cache") - 1,
sizeof("mrr_sort_keys") - 1,
#ifndef DBUG_OFF #ifndef DBUG_OFF
sizeof("table_elimination") - 1, sizeof("table_elimination") - 1,
#endif #endif
...@@ -415,7 +417,8 @@ static const char *optimizer_switch_str="index_merge=on,index_merge_union=on," ...@@ -415,7 +417,8 @@ static const char *optimizer_switch_str="index_merge=on,index_merge_union=on,"
"semijoin=on," "semijoin=on,"
"partial_match_rowid_merge=on," "partial_match_rowid_merge=on,"
"partial_match_table_scan=on," "partial_match_table_scan=on,"
"subquery_cache=on" "subquery_cache=on,"
"mrr_sort_keys=on"
#ifndef DBUG_OFF #ifndef DBUG_OFF
",table_elimination=on"; ",table_elimination=on";
#else #else
......
...@@ -651,6 +651,9 @@ int JOIN_CACHE_BKA::init() ...@@ -651,6 +651,9 @@ int JOIN_CACHE_BKA::init()
use_emb_key= check_emb_key_usage(); use_emb_key= check_emb_key_usage();
if (use_emb_key)
mrr_mode|= HA_MRR_MATERIALIZED_KEYS;
create_remaining_fields(FALSE); create_remaining_fields(FALSE);
set_constants(); set_constants();
...@@ -2631,6 +2634,8 @@ int JOIN_CACHE_BKA_UNIQUE::init() ...@@ -2631,6 +2634,8 @@ int JOIN_CACHE_BKA_UNIQUE::init()
data_fields_offset+= copy->length; data_fields_offset+= copy->length;
} }
mrr_mode|= HA_MRR_MATERIALIZED_KEYS;
DBUG_RETURN(rc); DBUG_RETURN(rc);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment