mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
Post-merge fixes and code cleanup
This commit is contained in:
@ -7,7 +7,7 @@ filler char(200),
|
|||||||
filler2 char(200),
|
filler2 char(200),
|
||||||
index(key1),
|
index(key1),
|
||||||
index(key2),
|
index(key2),
|
||||||
) type=bdb;
|
) engine=bdb;
|
||||||
select * from t1 where (key1 >= 2 and key1 <= 10) or (pk >= 4 and pk <=8 );
|
select * from t1 where (key1 >= 2 and key1 <= 10) or (pk >= 4 and pk <=8 );
|
||||||
pk key1 key2 filler filler2
|
pk key1 key2 filler filler2
|
||||||
2 2 2 filler-data filler-data-2
|
2 2 2 filler-data filler-data-2
|
||||||
|
@ -7,7 +7,7 @@ filler char(200),
|
|||||||
filler2 char(200),
|
filler2 char(200),
|
||||||
index(key1),
|
index(key1),
|
||||||
index(key2),
|
index(key2),
|
||||||
) type=innodb;
|
) engine=innodb;
|
||||||
select * from t1 where (key1 >= 2 and key1 <= 10) or (pk >= 4 and pk <=8 );
|
select * from t1 where (key1 >= 2 and key1 <= 10) or (pk >= 4 and pk <=8 );
|
||||||
pk key1 key2 filler filler2
|
pk key1 key2 filler filler2
|
||||||
2 2 2 filler-data filler-data-2
|
2 2 2 filler-data filler-data-2
|
||||||
|
@ -15,7 +15,7 @@ create table t1 (
|
|||||||
filler2 char(200),
|
filler2 char(200),
|
||||||
index(key1),
|
index(key1),
|
||||||
index(key2),
|
index(key2),
|
||||||
) type=bdb;
|
) engine=bdb;
|
||||||
|
|
||||||
|
|
||||||
--disable_query_log
|
--disable_query_log
|
||||||
|
@ -15,7 +15,7 @@ create table t1 (
|
|||||||
filler2 char(200),
|
filler2 char(200),
|
||||||
index(key1),
|
index(key1),
|
||||||
index(key2),
|
index(key2),
|
||||||
) type=innodb;
|
) engine=innodb;
|
||||||
|
|
||||||
|
|
||||||
--disable_query_log
|
--disable_query_log
|
||||||
|
@ -274,7 +274,11 @@ class SEL_TREE :public Sql_alloc
|
|||||||
public:
|
public:
|
||||||
enum Type { IMPOSSIBLE, ALWAYS, MAYBE, KEY, KEY_SMALLER } type;
|
enum Type { IMPOSSIBLE, ALWAYS, MAYBE, KEY, KEY_SMALLER } type;
|
||||||
SEL_TREE(enum Type type_arg) :type(type_arg) {}
|
SEL_TREE(enum Type type_arg) :type(type_arg) {}
|
||||||
SEL_TREE() :type(KEY) { keys_map.clear_all(); bzero((char*) keys,sizeof(keys));}
|
SEL_TREE() :type(KEY)
|
||||||
|
{
|
||||||
|
keys_map.clear_all();
|
||||||
|
bzero((char*) keys,sizeof(keys));
|
||||||
|
}
|
||||||
SEL_ARG *keys[MAX_KEY];
|
SEL_ARG *keys[MAX_KEY];
|
||||||
key_map keys_map; /* bitmask of non-NULL elements in keys */
|
key_map keys_map; /* bitmask of non-NULL elements in keys */
|
||||||
List<SEL_IMERGE> merges; /* possible ways to read rows using index_merge */
|
List<SEL_IMERGE> merges; /* possible ways to read rows using index_merge */
|
||||||
@ -306,7 +310,8 @@ static ha_rows check_quick_keys(PARAM *param,uint index,SEL_ARG *key_tree,
|
|||||||
char *max_key, uint max_key_flag);
|
char *max_key, uint max_key_flag);
|
||||||
|
|
||||||
QUICK_RANGE_SELECT *get_quick_select(PARAM *param,uint index,
|
QUICK_RANGE_SELECT *get_quick_select(PARAM *param,uint index,
|
||||||
SEL_ARG *key_tree, MEM_ROOT *alloc = NULL);
|
SEL_ARG *key_tree,
|
||||||
|
MEM_ROOT *alloc = NULL);
|
||||||
static int get_quick_select_params(SEL_TREE *tree, PARAM *param,
|
static int get_quick_select_params(SEL_TREE *tree, PARAM *param,
|
||||||
key_map& needed_reg,
|
key_map& needed_reg,
|
||||||
bool index_read_can_be_used,
|
bool index_read_can_be_used,
|
||||||
@ -338,7 +343,8 @@ bool get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key,
|
|||||||
static bool eq_tree(SEL_ARG* a,SEL_ARG *b);
|
static bool eq_tree(SEL_ARG* a,SEL_ARG *b);
|
||||||
|
|
||||||
static SEL_ARG null_element(SEL_ARG::IMPOSSIBLE);
|
static SEL_ARG null_element(SEL_ARG::IMPOSSIBLE);
|
||||||
static bool null_part_in_key(KEY_PART *key_part, const char *key, uint length);
|
static bool null_part_in_key(KEY_PART *key_part, const char *key,
|
||||||
|
uint length);
|
||||||
bool sel_trees_can_be_ored(SEL_TREE *tree1, SEL_TREE *tree2, PARAM* param);
|
bool sel_trees_can_be_ored(SEL_TREE *tree1, SEL_TREE *tree2, PARAM* param);
|
||||||
|
|
||||||
|
|
||||||
@ -620,7 +626,7 @@ QUICK_SELECT_I::QUICK_SELECT_I()
|
|||||||
|
|
||||||
QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(THD *thd, TABLE *table, uint key_nr,
|
QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(THD *thd, TABLE *table, uint key_nr,
|
||||||
bool no_alloc, MEM_ROOT *parent_alloc)
|
bool no_alloc, MEM_ROOT *parent_alloc)
|
||||||
:dont_free(0),error(0),range(0),cur_range(NULL)
|
:dont_free(0),error(0),cur_range(NULL),range(0)
|
||||||
{
|
{
|
||||||
index= key_nr;
|
index= key_nr;
|
||||||
head= table;
|
head= table;
|
||||||
@ -654,9 +660,10 @@ QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QUICK_INDEX_MERGE_SELECT::QUICK_INDEX_MERGE_SELECT(THD *thd_param, TABLE *table)
|
QUICK_INDEX_MERGE_SELECT::QUICK_INDEX_MERGE_SELECT(THD *thd_param,
|
||||||
:cur_quick_it(quick_selects), thd(thd_param), unique(NULL),
|
TABLE *table)
|
||||||
pk_quick_select(NULL)
|
:cur_quick_it(quick_selects),pk_quick_select(NULL),unique(NULL),
|
||||||
|
thd(thd_param)
|
||||||
{
|
{
|
||||||
index= MAX_KEY;
|
index= MAX_KEY;
|
||||||
head= table;
|
head= table;
|
||||||
@ -1231,7 +1238,7 @@ static int get_index_merge_params(PARAM *param, key_map& needed_reg,
|
|||||||
double tree_read_time;
|
double tree_read_time;
|
||||||
ha_rows tree_records;
|
ha_rows tree_records;
|
||||||
bool pk_is_clustered= param->table->file->primary_key_is_clustered();
|
bool pk_is_clustered= param->table->file->primary_key_is_clustered();
|
||||||
bool have_cpk_scan;
|
bool have_cpk_scan= false;
|
||||||
ha_rows records_for_unique= 0;
|
ha_rows records_for_unique= 0;
|
||||||
ha_rows cpk_records= 0;
|
ha_rows cpk_records= 0;
|
||||||
|
|
||||||
@ -1296,6 +1303,7 @@ static int get_index_merge_params(PARAM *param, key_map& needed_reg,
|
|||||||
records_for_unique += tree_records;
|
records_for_unique += tree_records;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
DBUG_PRINT("info",("index_merge cost of index reads: %g", imerge_cost));
|
||||||
|
|
||||||
if (imerge_too_expensive)
|
if (imerge_too_expensive)
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
@ -1330,32 +1338,36 @@ static int get_index_merge_params(PARAM *param, key_map& needed_reg,
|
|||||||
{
|
{
|
||||||
double n_blocks=
|
double n_blocks=
|
||||||
ceil((double)(longlong)param->table->file->data_file_length / IO_SIZE);
|
ceil((double)(longlong)param->table->file->data_file_length / IO_SIZE);
|
||||||
/* Don't ceil the following as it is an estimate */
|
|
||||||
double busy_blocks=
|
double busy_blocks=
|
||||||
n_blocks * (1.0 - pow(1.0 - 1.0/n_blocks, records_for_unique));
|
n_blocks * (1.0 - pow(1.0 - 1.0/n_blocks, records_for_unique));
|
||||||
|
|
||||||
JOIN *join= param->thd->lex->select_lex.join;
|
JOIN *join= param->thd->lex->select_lex.join;
|
||||||
if (!join || join->tables == 1)
|
if (!join || join->tables == 1)
|
||||||
{
|
|
||||||
imerge_cost += busy_blocks*(DISK_SEEK_BASE_COST +
|
imerge_cost += busy_blocks*(DISK_SEEK_BASE_COST +
|
||||||
DISK_SEEK_PROP_COST*n_blocks/busy_blocks);
|
DISK_SEEK_PROP_COST*n_blocks/busy_blocks);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
It can be a join with source table being non-last table, so assume
|
It can be a join with source table being non-last table, so assume
|
||||||
that disk seeks are random here.
|
that disk seeks are random here.
|
||||||
(TODO it is possible to determine if this *is* a last table in 'index
|
(TODO it is possible to determine if this is a last table in 'index
|
||||||
checked for each record'-type join)
|
checked for each record' join)
|
||||||
*/
|
*/
|
||||||
imerge_cost += busy_blocks;
|
imerge_cost += busy_blocks;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
DBUG_PRINT("info",("index_merge cost with rowid-to-row scan: %g", imerge_cost));
|
||||||
|
|
||||||
/* PHASE 3: Add Unique operations cost */
|
/* PHASE 3: Add Unique operations cost */
|
||||||
imerge_cost += Unique::get_use_cost(param->mem_root, records_for_unique,
|
double unique_cost=
|
||||||
|
Unique::get_use_cost(param->mem_root, records_for_unique,
|
||||||
param->table->file->ref_length,
|
param->table->file->ref_length,
|
||||||
param->thd->variables.sortbuff_size);
|
param->thd->variables.sortbuff_size);
|
||||||
|
if (unique_cost < 0.0)
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
|
imerge_cost += unique_cost;
|
||||||
|
DBUG_PRINT("info",("index_merge total cost: %g", imerge_cost));
|
||||||
if (imerge_cost < *read_time)
|
if (imerge_cost < *read_time)
|
||||||
{
|
{
|
||||||
*read_time= imerge_cost;
|
*read_time= imerge_cost;
|
||||||
@ -1382,7 +1394,8 @@ static int get_index_merge_params(PARAM *param, key_map& needed_reg,
|
|||||||
key blocks are half full (normally things are much better).
|
key blocks are half full (normally things are much better).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
inline double get_index_only_read_time(PARAM* param, ha_rows records, int keynr)
|
inline double get_index_only_read_time(PARAM* param, ha_rows records,
|
||||||
|
int keynr)
|
||||||
{
|
{
|
||||||
double read_time;
|
double read_time;
|
||||||
uint keys_per_block= (param->table->file->block_size/2/
|
uint keys_per_block= (param->table->file->block_size/2/
|
||||||
@ -1445,12 +1458,7 @@ static int get_quick_select_params(SEL_TREE *tree, PARAM *param,
|
|||||||
read_index_only &&
|
read_index_only &&
|
||||||
(param->table->file->index_flags(keynr) & HA_KEY_READ_ONLY))
|
(param->table->file->index_flags(keynr) & HA_KEY_READ_ONLY))
|
||||||
{
|
{
|
||||||
/*
|
/* We can resolve this by only reading through this key. */
|
||||||
We can resolve this by only reading through this key.
|
|
||||||
Assume that we will read trough the whole key range
|
|
||||||
and that all key blocks are half full (normally things are
|
|
||||||
much better).
|
|
||||||
*/
|
|
||||||
found_read_time=get_index_only_read_time(param, found_records, keynr);
|
found_read_time=get_index_only_read_time(param, found_records, keynr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -3893,7 +3901,8 @@ static void print_quick_sel_imerge(QUICK_INDEX_MERGE_SELECT *quick,
|
|||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_quick_sel_range(QUICK_RANGE_SELECT *quick,const key_map *needed_reg)
|
void print_quick_sel_range(QUICK_RANGE_SELECT *quick,
|
||||||
|
const key_map *needed_reg)
|
||||||
{
|
{
|
||||||
QUICK_RANGE *range;
|
QUICK_RANGE *range;
|
||||||
char buf[MAX_KEY/8+1];
|
char buf[MAX_KEY/8+1];
|
||||||
|
@ -76,7 +76,9 @@ Unique::Unique(qsort_cmp2 comp_func, void * comp_func_fixed_arg,
|
|||||||
#define M_PI 3.14159265358979323846
|
#define M_PI 3.14159265358979323846
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define M_E (exp(1))
|
#ifndef M_E
|
||||||
|
#define M_E (exp((double)1.0))
|
||||||
|
#endif
|
||||||
|
|
||||||
inline double log2_n_fact(double x)
|
inline double log2_n_fact(double x)
|
||||||
{
|
{
|
||||||
@ -174,7 +176,8 @@ static double get_merge_many_buffs_cost(MEM_ROOT *alloc,
|
|||||||
key_size using max_in_memory_size memory.
|
key_size using max_in_memory_size memory.
|
||||||
|
|
||||||
RETURN
|
RETURN
|
||||||
Use cost as # of disk seeks.
|
>=0 Cost in disk seeks.
|
||||||
|
<0 Out of memory.
|
||||||
|
|
||||||
NOTES
|
NOTES
|
||||||
cost(using_unqiue) =
|
cost(using_unqiue) =
|
||||||
@ -229,19 +232,28 @@ double Unique::get_use_cost(MEM_ROOT *alloc, uint nkeys, uint key_size,
|
|||||||
result+= n_full_trees * log2_n_fact(max_elements_in_tree);
|
result+= n_full_trees * log2_n_fact(max_elements_in_tree);
|
||||||
result /= TIME_FOR_COMPARE_ROWID;
|
result /= TIME_FOR_COMPARE_ROWID;
|
||||||
|
|
||||||
/* Calculate cost of merging */
|
DBUG_PRINT("info",("unique trees sizes: %u=%u*%lu + %lu", nkeys,
|
||||||
|
n_full_trees, n_full_trees?max_elements_in_tree:0,
|
||||||
|
last_tree_elems));
|
||||||
|
|
||||||
if (!n_full_trees)
|
if (!n_full_trees)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
/* There is more then one tree and merging is necessary. */
|
/*
|
||||||
/* Add cost of writing all trees to disk. */
|
There is more then one tree and merging is necessary.
|
||||||
|
First, add cost of writing all trees to disk.
|
||||||
|
*/
|
||||||
result += n_full_trees * ceil(key_size*max_elements_in_tree / IO_SIZE);
|
result += n_full_trees * ceil(key_size*max_elements_in_tree / IO_SIZE);
|
||||||
result += ceil(key_size*last_tree_elems / IO_SIZE);
|
result += ceil(key_size*last_tree_elems / IO_SIZE);
|
||||||
|
|
||||||
/* Cost of merge */
|
/* Cost of merge */
|
||||||
result += get_merge_many_buffs_cost(alloc, n_full_trees,
|
double merge_cost= get_merge_many_buffs_cost(alloc, n_full_trees,
|
||||||
max_elements_in_tree,
|
max_elements_in_tree,
|
||||||
last_tree_elems, key_size);
|
last_tree_elems, key_size);
|
||||||
|
if (merge_cost < 0.0)
|
||||||
|
return merge_cost;
|
||||||
|
|
||||||
|
result += merge_cost;
|
||||||
/*
|
/*
|
||||||
Add cost of reading the resulting sequence, assuming there were no
|
Add cost of reading the resulting sequence, assuming there were no
|
||||||
duplicate elements.
|
duplicate elements.
|
||||||
|
Reference in New Issue
Block a user