3480 Jorgen Loland 2011-11-08
WL#5860: Make COST_VECT a properly encapsulated C++ class
This changeset:
* Changes name of COST_VECT to Cost_estimate
* Encapsulates variables
* Merges io_count and io_avg_cost into one variable: io_cost
* Modifies code that used COST_VECT to use Cost_estimate instead
* Adds unit tests for the Cost_estimate class
This changeset does NOT change any cost calculations. It is
purely a refactoring to an encapsulated C++ class following
our coding guidelines.
@ sql/handler.cc
Refactoring: Move from COST_VECT to Cost_estimate
@ sql/handler.h
Refactoring: Make COST_VECT a properly encapsulated C++ class
with name Cost_estimate
@ sql/opt_range.cc
Refactoring: Move from COST_VECT to Cost_estimate
@ sql/sql_select.cc
Refactoring: Move from COST_VECT to Cost_estimate
@ sql/sql_select.h
Refactoring: Move from COST_VECT to Cost_estimate
@ sql/table.h
Refactoring: Move from COST_VECT to Cost_estimate
@ storage/innobase/handler/ha_innodb.cc
Refactoring: Move from COST_VECT to Cost_estimate
@ storage/innobase/handler/ha_innodb.h
Refactoring: Move from COST_VECT to Cost_estimate
@ storage/myisam/ha_myisam.cc
Refactoring: Move from COST_VECT to Cost_estimate
@ storage/myisam/ha_myisam.h
Refactoring: Move from COST_VECT to Cost_estimate
@ unittest/gunit/CMakeLists.txt
Added gunit test file: cost_estimate
@ unittest/gunit/cost_estimate-t.cc
Unit tests for class Cost_estimate
added:
unittest/gunit/cost_estimate-t.cc
modified:
sql/handler.cc
sql/handler.h
sql/opt_range.cc
sql/sql_select.cc
sql/sql_select.h
sql/table.h
storage/innobase/handler/ha_innodb.cc
storage/innobase/handler/ha_innodb.h
storage/myisam/ha_myisam.cc
storage/myisam/ha_myisam.h
unittest/gunit/CMakeLists.txt
3479 Oystein Grovlen 2011-11-08
WL#5559 - Factor tmp table out of optimizer.
Part 3: Unify the code for creation of temporary tables
for GROUP BY/ORDER BY
Changed JOIN::create_intermediate_table() so that it
can be used to create both temporary tables, and let it
return a pointer to the created table, and use it to also
create JOIN::exec_tmp_table2.
@ sql/sql_select.cc
1. Extended JOIN::create_intermediate_table() with parameters
for characteristics that vary between the two temporary
tables.
2. Changed JOIN::create_intermediate_table() to return the
pointer to the created temporary table, instead of
assigning it to exec_tmp_table1.
3. Moved code in JOIN::create_intermediate_table() that are
only relevant to exec_tmp_table1 to JOIN::exec().
4. Moved code in JOIN::create_intermediate_table() related
to optimization for distinct to a new private function
JOIN::optimize_distinct(). (To be called from
JOIN::exec() after creating the exec_tmp_table1
for time being, but longer term this should be moved to
optimization phase.)
5. Call create_intermediate_table() to create
exec_tmp_table2.
@ sql/sql_select.h
Created new private function JOIN::optimize_distinct() to optimize
distinct when used on a subset of tables in query.
Changed signature of JOIN::create_intermediate table to be able to
handle creation of both temporary tables used for sorting.
modified:
sql/sql_select.cc
sql/sql_select.h
=== modified file 'sql/handler.cc'
--- a/sql/handler.cc 2011-10-21 14:59:52 +0000
+++ b/sql/handler.cc 2011-11-08 11:37:54 +0000
@@ -4563,7 +4563,8 @@ bool key_uses_partial_cols(TABLE *table,
ha_rows
handler::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
void *seq_init_param, uint n_ranges_arg,
- uint *bufsz, uint *flags, COST_VECT *cost)
+ uint *bufsz, uint *flags,
+ Cost_estimate *cost)
{
KEY_MULTI_RANGE range;
range_seq_t seq_it;
@@ -4613,13 +4614,14 @@ handler::multi_range_read_info_const(uin
{
/* The following calculation is the same as in multi_range_read_info(): */
*flags |= HA_MRR_USE_DEFAULT_IMPL;
- cost->zero();
- cost->avg_io_cost= 1; /* assume random seeks */
+ DBUG_ASSERT(cost->is_zero());
if ((*flags & HA_MRR_INDEX_ONLY) && total_rows > 2)
- cost->io_count= index_only_read_time(keyno, total_rows);
+ cost->add_io(index_only_read_time(keyno, total_rows) *
+ Cost_estimate::IO_BLOCK_READ_COST());
else
- cost->io_count= read_time(keyno, n_ranges, total_rows);
- cost->cpu_cost= total_rows * ROW_EVALUATE_COST + 0.01;
+ cost->add_io(read_time(keyno, n_ranges, total_rows) *
+ Cost_estimate::IO_BLOCK_READ_COST());
+ cost->add_cpu(total_rows * ROW_EVALUATE_COST + 0.01);
}
return total_rows;
}
@@ -4660,20 +4662,22 @@ handler::multi_range_read_info_const(uin
*/
ha_rows handler::multi_range_read_info(uint keyno, uint n_ranges, uint n_rows,
- uint *bufsz, uint *flags, COST_VECT *cost)
+ uint *bufsz, uint *flags,
+ Cost_estimate *cost)
{
*bufsz= 0; /* Default implementation doesn't need a buffer */
*flags |= HA_MRR_USE_DEFAULT_IMPL;
- cost->zero();
- cost->avg_io_cost= 1; /* assume random seeks */
+ DBUG_ASSERT(cost->is_zero());
/* Produce the same cost as non-MRR code does */
if (*flags & HA_MRR_INDEX_ONLY)
- cost->io_count= index_only_read_time(keyno, n_rows);
+ cost->add_io(index_only_read_time(keyno, n_rows) *
+ Cost_estimate::IO_BLOCK_READ_COST());
else
- cost->io_count= read_time(keyno, n_ranges, n_rows);
+ cost->add_io(read_time(keyno, n_ranges, n_rows) *
+ Cost_estimate::IO_BLOCK_READ_COST());
return 0;
}
@@ -5145,7 +5149,7 @@ end:
DS-MRR implementation: multi_range_read_info() function
*/
ha_rows DsMrr_impl::dsmrr_info(uint keyno, uint n_ranges, uint rows,
- uint *bufsz, uint *flags, COST_VECT *cost)
+ uint *bufsz, uint *flags, Cost_estimate *cost)
{
ha_rows res;
uint def_flags= *flags;
@@ -5179,7 +5183,7 @@ ha_rows DsMrr_impl::dsmrr_info(uint keyn
ha_rows DsMrr_impl::dsmrr_info_const(uint keyno, RANGE_SEQ_IF *seq,
void *seq_init_param, uint n_ranges,
- uint *bufsz, uint *flags, COST_VECT *cost)
+ uint *bufsz, uint *flags, Cost_estimate *cost)
{
ha_rows rows;
uint def_flags= *flags;
@@ -5240,9 +5244,8 @@ ha_rows DsMrr_impl::dsmrr_info_const(uin
*/
bool DsMrr_impl::choose_mrr_impl(uint keyno, ha_rows rows, uint *flags,
- uint *bufsz, COST_VECT *cost)
+ uint *bufsz, Cost_estimate *cost)
{
- COST_VECT dsmrr_cost;
bool res;
THD *thd= current_thd;
if (!thd->optimizer_switch_flag(OPTIMIZER_SWITCH_MRR) ||
@@ -5257,6 +5260,7 @@ bool DsMrr_impl::choose_mrr_impl(uint ke
uint add_len= table->key_info[keyno].key_length + h->ref_length;
*bufsz -= add_len;
+ Cost_estimate dsmrr_cost;
if (get_disk_sweep_mrr_cost(keyno, rows, *flags, bufsz, &dsmrr_cost))
return TRUE;
*bufsz += add_len;
@@ -5274,7 +5278,7 @@ bool DsMrr_impl::choose_mrr_impl(uint ke
dsmrr_cost.total_cost() > cost->total_cost())
dsmrr_cost= *cost;
- if (force_dsmrr || dsmrr_cost.total_cost() <= cost->total_cost())
+ if (force_dsmrr || (dsmrr_cost.total_cost() <= cost->total_cost()))
{
*flags &= ~HA_MRR_USE_DEFAULT_IMPL; /* Use the DS-MRR implementation */
*flags &= ~HA_MRR_SORTED; /* We will return unordered output */
@@ -5290,7 +5294,8 @@ bool DsMrr_impl::choose_mrr_impl(uint ke
}
-static void get_sort_and_sweep_cost(TABLE *table, ha_rows nrows, COST_VECT *cost);
+static void get_sort_and_sweep_cost(TABLE *table, ha_rows nrows,
+ Cost_estimate *cost);
/**
@@ -5308,7 +5313,8 @@ static void get_sort_and_sweep_cost(TABL
*/
bool DsMrr_impl::get_disk_sweep_mrr_cost(uint keynr, ha_rows rows, uint flags,
- uint *buffer_size, COST_VECT *cost)
+ uint *buffer_size,
+ Cost_estimate *cost)
{
ulong max_buff_entries, elem_size;
ha_rows rows_in_last_step;
@@ -5329,7 +5335,8 @@ bool DsMrr_impl::get_disk_sweep_mrr_cost
non-full buffer
*/
rows_in_last_step= rows % max_buff_entries;
-
+
+ DBUG_ASSERT(cost->is_zero());
/* Adjust buffer size if we expect to use only part of the buffer */
if (n_full_steps)
{
@@ -5338,24 +5345,35 @@ bool DsMrr_impl::get_disk_sweep_mrr_cost
}
else
{
- cost->zero();
*buffer_size= max(*buffer_size,
(size_t)(1.2*rows_in_last_step) * elem_size +
h->ref_length + table->key_info[keynr].key_length);
}
- COST_VECT last_step_cost;
+ Cost_estimate last_step_cost;
get_sort_and_sweep_cost(table, rows_in_last_step, &last_step_cost);
- cost->add(&last_step_cost);
+ (*cost)+= last_step_cost;
+ /*
+ With the old COST_VECT, memory cost was part of total_cost() but
+ that's not the case with Cost_estimate. Introducing Cost_estimate
+ shall not change any costs, hence the memory cost is added as if
+ it was CPU cost below. To be reconsidered when DsMRR costs are
+ refactored.
+ */
if (n_full_steps != 0)
- cost->mem_cost= *buffer_size;
+ {
+ cost->add_mem(*buffer_size);
+ cost->add_cpu(*buffer_size);
+ }
else
- cost->mem_cost= rows_in_last_step * elem_size;
-
+ {
+ cost->add_mem(rows_in_last_step * elem_size);
+ cost->add_cpu(rows_in_last_step * elem_size);
+ }
/* Total cost of all index accesses */
index_read_cost= h->index_only_read_time(keynr, rows);
- cost->add_io(index_read_cost, 1 /* Random seeks */);
+ cost->add_io(index_read_cost * Cost_estimate::IO_BLOCK_READ_COST());
return FALSE;
}
@@ -5376,8 +5394,9 @@ bool DsMrr_impl::get_disk_sweep_mrr_cost
*/
static
-void get_sort_and_sweep_cost(TABLE *table, ha_rows nrows, COST_VECT *cost)
+void get_sort_and_sweep_cost(TABLE *table, ha_rows nrows, Cost_estimate *cost)
{
+ DBUG_ASSERT(cost->is_zero());
if (nrows)
{
get_sweep_read_cost(table, nrows, FALSE, cost);
@@ -5385,10 +5404,8 @@ void get_sort_and_sweep_cost(TABLE *tabl
double cmp_op= rows2double(nrows) * ROWID_COMPARE_COST;
if (cmp_op < 3)
cmp_op= 3;
- cost->cpu_cost += cmp_op * log2(cmp_op);
+ cost->add_cpu(cmp_op * log2(cmp_op));
}
- else
- cost->zero();
}
@@ -5436,15 +5453,16 @@ void get_sort_and_sweep_cost(TABLE *tabl
*/
void get_sweep_read_cost(TABLE *table, ha_rows nrows, bool interrupted,
- COST_VECT *cost)
+ Cost_estimate *cost)
{
DBUG_ENTER("get_sweep_read_cost");
- cost->zero();
+ DBUG_ASSERT(cost->is_zero());
if (table->file->primary_key_is_clustered())
{
- cost->io_count= table->file->read_time(table->s->primary_key, (uint)nrows,
- nrows);
+ cost->add_io(table->file->read_time(table->s->primary_key,
+ (uint)nrows, nrows) *
+ Cost_estimate::IO_BLOCK_READ_COST());
}
else
{
@@ -5459,14 +5477,13 @@ void get_sweep_read_cost(TABLE *table, h
DBUG_PRINT("info",("sweep: nblocks=%g, busy_blocks=%g", n_blocks,
busy_blocks));
- cost->io_count= busy_blocks;
-
- if (!interrupted)
- {
+ if (interrupted)
+ cost->add_io(busy_blocks * Cost_estimate::IO_BLOCK_READ_COST());
+ else
/* Assume reading is done in one 'sweep' */
- cost->avg_io_cost= (DISK_SEEK_BASE_COST +
- DISK_SEEK_PROP_COST*n_blocks/busy_blocks);
- }
+ cost->add_io(busy_blocks *
+ (DISK_SEEK_BASE_COST +
+ DISK_SEEK_PROP_COST * n_blocks / busy_blocks));
}
DBUG_PRINT("info",("returning cost=%g", cost->total_cost()));
DBUG_VOID_RETURN;
=== modified file 'sql/handler.h'
--- a/sql/handler.h 2011-10-21 14:59:52 +0000
+++ b/sql/handler.h 2011-11-08 11:37:54 +0000
@@ -1053,73 +1053,96 @@ typedef struct st_range_seq_if
uint16 &mrr_persistent_flag_storage(range_seq_t seq, uint idx);
char* &mrr_get_ptr_by_idx(range_seq_t seq, uint idx);
-class COST_VECT
+/**
+ Used to store optimizer cost estimates.
+
+ The class consists of PODs only: default operator=, copy constructor
+ and destructor are used.
+ */
+class Cost_estimate
{
-public:
- double io_count; /* number of I/O */
- double avg_io_cost; /* cost of an average I/O oper. */
- double cpu_cost; /* cost of operations in CPU */
- double mem_cost; /* cost of used memory */
- double import_cost; /* cost of remote operations */
+private:
+ double io_cost; ///< cost of I/O operations
+ double cpu_cost; ///< cost of CPU operations
+ double import_cost; ///< cost of remote operations
+ double mem_cost; ///< memory used (bytes)
- enum { IO_COEFF=1 };
- enum { CPU_COEFF=1 };
- enum { MEM_COEFF=1 };
- enum { IMPORT_COEFF=1 };
+public:
- COST_VECT() { zero(); } // keep gcc happy
+ /// The cost of one I/O operation
+ static double IO_BLOCK_READ_COST() { return 1.0; }
- double total_cost()
- {
- return IO_COEFF*io_count*avg_io_cost + CPU_COEFF * cpu_cost +
- MEM_COEFF*mem_cost + IMPORT_COEFF*import_cost;
+ Cost_estimate() :
+ io_cost(0),
+ cpu_cost(0),
+ import_cost(0),
+ mem_cost(0)
+ {}
+
+ /// Returns sum of time-consuming costs, i.e., not counting memory cost
+ double total_cost() const { return io_cost + cpu_cost + import_cost; }
+ double get_io_cost() const { return io_cost; }
+ double get_cpu_cost() const { return cpu_cost; }
+ double get_import_cost() const { return import_cost; }
+ double get_mem_cost() const { return mem_cost; }
+
+ /**
+ Whether or not all costs in the object are zero
+
+ @return true if all costs are zero, false otherwise
+ */
+ bool is_zero() const
+ {
+ return !(io_cost || cpu_cost || import_cost || mem_cost);
}
- void zero()
+ /// Reset all costs to zero
+ void reset()
{
- avg_io_cost= 1.0;
- io_count= cpu_cost= mem_cost= import_cost= 0.0;
+ io_cost= cpu_cost= import_cost= mem_cost= 0;
}
+ /// Multiply io, cpu and import costs by parameter
void multiply(double m)
{
- io_count *= m;
+ io_cost *= m;
cpu_cost *= m;
import_cost *= m;
/* Don't multiply mem_cost */
}
- void add(const COST_VECT* cost)
+ Cost_estimate& operator+= (const Cost_estimate &other)
{
- double io_count_sum= io_count + cost->io_count;
- add_io(cost->io_count, cost->avg_io_cost);
- io_count= io_count_sum;
- cpu_cost += cost->cpu_cost;
- }
- void add_io(double add_io_cnt, double add_avg_cost)
- {
- double io_count_sum= io_count + add_io_cnt;
- if (io_count_sum != 0.0)
- avg_io_cost= (io_count * avg_io_cost +
- add_io_cnt * add_avg_cost) / io_count_sum;
- DBUG_ASSERT(!isnan(avg_io_cost));
- io_count= io_count_sum;
+ io_cost+= other.io_cost;
+ cpu_cost+= other.cpu_cost;
+ import_cost+= other.import_cost;
+ mem_cost+= other.mem_cost;
+
+ return *this;
}
- /*
- To be used when we go from old single value-based cost calculations to
- the new COST_VECT-based.
- */
- void convert_from_cost(double cost)
+ Cost_estimate operator+ (const Cost_estimate &other)
{
- zero();
- avg_io_cost= 1.0;
- io_count= cost;
+ Cost_estimate result= *this;
+ result+= other;
+ return result;
}
+
+ /// Add to IO cost
+ void add_io(double add_io_cost) { io_cost+= add_io_cost; }
+
+ /// Add to CPU cost
+ void add_cpu(double add_cpu_cost) { cpu_cost+= add_cpu_cost; }
+
+ /// Add to import cost
+ void add_import(double add_import_cost) { import_cost+= add_import_cost; }
+
+ /// Add to memory cost
+ void add_mem(double add_mem_cost) { mem_cost+= add_mem_cost; }
};
void get_sweep_read_cost(TABLE *table, ha_rows nrows, bool interrupted,
- COST_VECT *cost);
+ Cost_estimate *cost);
/*
The below two are not used (and not handled) in this milestone of this WL
@@ -1595,9 +1618,11 @@ public:
virtual ha_rows multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
void *seq_init_param,
uint n_ranges, uint *bufsz,
- uint *flags, COST_VECT *cost);
+ uint *flags,
+ Cost_estimate *cost);
virtual ha_rows multi_range_read_info(uint keyno, uint n_ranges, uint keys,
- uint *bufsz, uint *flags, COST_VECT *cost);
+ uint *bufsz, uint *flags,
+ Cost_estimate *cost);
virtual int multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param,
uint n_ranges, uint mode,
HANDLER_BUFFER *buf);
@@ -2440,16 +2465,16 @@ public:
int dsmrr_next(char **range_info);
ha_rows dsmrr_info(uint keyno, uint n_ranges, uint keys, uint *bufsz,
- uint *flags, COST_VECT *cost);
+ uint *flags, Cost_estimate *cost);
ha_rows dsmrr_info_const(uint keyno, RANGE_SEQ_IF *seq,
void *seq_init_param, uint n_ranges, uint *bufsz,
- uint *flags, COST_VECT *cost);
+ uint *flags, Cost_estimate *cost);
private:
bool choose_mrr_impl(uint keyno, ha_rows rows, uint *flags, uint *bufsz,
- COST_VECT *cost);
+ Cost_estimate *cost);
bool get_disk_sweep_mrr_cost(uint keynr, ha_rows rows, uint flags,
- uint *buffer_size, COST_VECT *cost);
+ uint *buffer_size, Cost_estimate *cost);
};
/* Some extern variables used with handlers */
=== modified file 'sql/opt_range.cc'
--- a/sql/opt_range.cc 2011-11-07 14:00:01 +0000
+++ b/sql/opt_range.cc 2011-11-08 11:37:54 +0000
@@ -840,7 +840,7 @@ static bool is_key_scan_ror(PARAM *param
static ha_rows check_quick_select(PARAM *param, uint idx, bool index_only,
SEL_ARG *tree, bool update_tbl_stats,
uint *mrr_flags, uint *bufsize,
- COST_VECT *cost);
+ Cost_estimate *cost);
QUICK_RANGE_SELECT *get_quick_select(PARAM *param,uint index,
SEL_ARG *key_tree, uint mrr_flags,
uint mrr_buf_size, MEM_ROOT *alloc);
@@ -4281,7 +4281,7 @@ TABLE_READ_PLAN *get_best_disjunct_quick
/* Calculate cost(rowid_to_row_scan) */
{
- COST_VECT sweep_cost;
+ Cost_estimate sweep_cost;
JOIN *join= param->thd->lex->select_lex.join;
bool is_interrupted= test(join && join->tables != 1);
get_sweep_read_cost(param->table, non_cpk_scan_records, is_interrupted,
@@ -4429,7 +4429,7 @@ skip_to_ror_scan:
*/
double roru_total_cost;
{
- COST_VECT sweep_cost;
+ Cost_estimate sweep_cost;
JOIN *join= param->thd->lex->select_lex.join;
bool is_interrupted= test(join && join->tables != 1);
get_sweep_read_cost(param->table, roru_total_records, is_interrupted,
@@ -4893,7 +4893,7 @@ static bool ror_intersect_add(ROR_INTERS
DBUG_PRINT("info", ("info->total_cost: %g", info->total_cost));
if (!info->is_covering)
{
- COST_VECT sweep_cost;
+ Cost_estimate sweep_cost;
JOIN *join= info->param->thd->lex->select_lex.join;
bool is_interrupted= test(join && join->tables == 1);
get_sweep_read_cost(info->param->table, double2rows(info->out_rows),
@@ -5420,7 +5420,7 @@ static TRP_RANGE *get_key_scans_params(P
if (*key)
{
ha_rows found_records;
- COST_VECT cost;
+ Cost_estimate cost;
double found_read_time;
uint mrr_flags, buf_size;
uint keynr= param->real_keynr[idx];
@@ -8659,7 +8659,7 @@ walk_up_n_right:
static
ha_rows check_quick_select(PARAM *param, uint idx, bool index_only,
SEL_ARG *tree, bool update_tbl_stats,
- uint *mrr_flags, uint *bufsize, COST_VECT *cost)
+ uint *mrr_flags, uint *bufsize, Cost_estimate *cost)
{
SEL_ARG_RANGE_SEQ seq;
RANGE_SEQ_IF seq_if = {sel_arg_range_seq_init, sel_arg_range_seq_next, 0, 0};
@@ -9155,7 +9155,7 @@ QUICK_RANGE_SELECT *get_quick_select_for
QUICK_RANGE *range;
uint part;
bool create_err= FALSE;
- COST_VECT cost;
+ Cost_estimate cost;
old_root= thd->mem_root;
/* The following call may change thd->mem_root */
@@ -10904,7 +10904,7 @@ get_best_group_min_max(PARAM *param, SEL
cur_index_tree= get_index_range_tree(cur_index, tree, param,
&cur_param_idx);
/* Check if this range tree can be used for prefix retrieval. */
- COST_VECT dummy_cost;
+ Cost_estimate dummy_cost;
uint mrr_flags= HA_MRR_USE_DEFAULT_IMPL;
uint mrr_bufsize=0;
cur_quick_prefix_records= check_quick_select(param, cur_param_idx,
=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc 2011-11-08 10:20:56 +0000
+++ b/sql/sql_select.cc 2011-11-08 11:37:54 +0000
@@ -5875,10 +5875,16 @@ static bool optimize_semijoin_nests_for_
sizeof(st_position) * n_tables);
sj_nest->nested_join->sjm.expected_rowcount= distinct_rowcount;
+ sj_nest->nested_join->sjm.materialization_cost.reset();
sj_nest->nested_join->sjm.materialization_cost
- .convert_from_cost(sjm_cost);
- sj_nest->nested_join->sjm.scan_cost.convert_from_cost(scan_cost);
- sj_nest->nested_join->sjm.lookup_cost.convert_from_cost(row_cost);
+ .add_io(sjm_cost);
+
+ sj_nest->nested_join->sjm.scan_cost.reset();
+ if (sj_nest->nested_join->sjm.expected_rowcount > 0.0)
+ sj_nest->nested_join->sjm.scan_cost.add_io(scan_cost);
+
+ sj_nest->nested_join->sjm.lookup_cost.reset();
+ sj_nest->nested_join->sjm.lookup_cost.add_io(row_cost);
}
}
}
@@ -11980,7 +11986,7 @@ static bool setup_join_buffering(JOIN_TA
bool *icp_other_tables_ok)
{
uint flags;
- COST_VECT cost;
+ Cost_estimate cost;
ha_rows rows;
uint bufsz= 4096;
JOIN_CACHE *prev_cache;
@@ -15847,7 +15853,8 @@ void Optimize_table_order::advance_sj_st
DBUG_ENTER("Optimize_table_order::advance_sj_state");
- pos->prefix_cost.convert_from_cost(*current_cost);
+ pos->prefix_cost.reset();
+ pos->prefix_cost.add_io(*current_cost);
pos->prefix_record_count= *current_rowcount;
Opt_trace_array trace_choices(trace, "semijoin_strategy_choice");
@@ -16232,7 +16239,8 @@ void Optimize_table_order::advance_sj_st
*/
if (sj_strategy != SJ_OPT_NONE)
{
- pos->prefix_cost.convert_from_cost(*current_cost);
+ pos->prefix_cost.reset();
+ pos->prefix_cost.add_io(*current_cost);
pos->prefix_record_count= *current_rowcount;
}
=== modified file 'sql/sql_select.h'
--- a/sql/sql_select.h 2011-11-08 10:20:56 +0000
+++ b/sql/sql_select.h 2011-11-08 11:37:54 +0000
@@ -1588,7 +1588,7 @@ typedef struct st_position : public Sql_
/* These form a stack of partial join order costs and output sizes */
- COST_VECT prefix_cost;
+ Cost_estimate prefix_cost;
double prefix_record_count;
/*
=== modified file 'sql/table.h'
--- a/sql/table.h 2011-10-18 14:25:42 +0000
+++ b/sql/table.h 2011-11-08 11:37:54 +0000
@@ -2080,11 +2080,11 @@ struct Semijoin_mat_optimize
/* Expected #rows in the materialized table */
double expected_rowcount;
/* Materialization cost - execute sub-join and write rows to temp.table */
- COST_VECT materialization_cost;
+ Cost_estimate materialization_cost;
/* Cost to make one lookup in the temptable */
- COST_VECT lookup_cost;
+ Cost_estimate lookup_cost;
/* Cost of scanning the materialized table */
- COST_VECT scan_cost;
+ Cost_estimate scan_cost;
};
typedef struct st_nested_join
=== modified file 'storage/innobase/handler/ha_innodb.cc'
--- a/storage/innobase/handler/ha_innodb.cc 2011-10-27 08:20:56 +0000
+++ b/storage/innobase/handler/ha_innodb.cc 2011-11-08 11:37:54 +0000
@@ -13389,7 +13389,7 @@ ha_innobase::multi_range_read_info_const
uint n_ranges,
uint* bufsz,
uint* flags,
- COST_VECT* cost)
+ Cost_estimate* cost)
{
/* See comments in ha_myisam::multi_range_read_info_const */
ds_mrr.init(this, table);
@@ -13404,7 +13404,7 @@ ha_innobase::multi_range_read_info(
uint keys,
uint* bufsz,
uint* flags,
- COST_VECT* cost)
+ Cost_estimate* cost)
{
ds_mrr.init(this, table);
return(ds_mrr.dsmrr_info(keyno, n_ranges, keys, bufsz, flags, cost));
=== modified file 'storage/innobase/handler/ha_innodb.h'
--- a/storage/innobase/handler/ha_innodb.h 2011-10-21 14:59:52 +0000
+++ b/storage/innobase/handler/ha_innodb.h 2011-11-08 11:37:54 +0000
@@ -265,7 +265,7 @@ public:
ha_rows multi_range_read_info_const(uint keyno, RANGE_SEQ_IF* seq,
void* seq_init_param,
uint n_ranges, uint* bufsz,
- uint* flags, COST_VECT* cost);
+ uint* flags, Cost_estimate* cost);
/** Initialize multi range read and get information.
* @see DsMrr_impl::dsmrr_info
* @param keyno
@@ -278,7 +278,7 @@ public:
*/
ha_rows multi_range_read_info(uint keyno, uint n_ranges, uint keys,
uint* bufsz, uint* flags,
- COST_VECT* cost);
+ Cost_estimate* cost);
/** Attempt to push down an index condition.
* @param[in] keyno MySQL key number
=== modified file 'storage/myisam/ha_myisam.cc'
--- a/storage/myisam/ha_myisam.cc 2011-10-21 05:42:01 +0000
+++ b/storage/myisam/ha_myisam.cc 2011-11-08 11:37:54 +0000
@@ -2147,7 +2147,7 @@ int ha_myisam::multi_range_read_next(cha
ha_rows ha_myisam::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
void *seq_init_param,
uint n_ranges, uint *bufsz,
- uint *flags, COST_VECT *cost)
+ uint *flags, Cost_estimate *cost)
{
/*
This call is here because there is no location where this->table would
@@ -2161,7 +2161,7 @@ ha_rows ha_myisam::multi_range_read_info
ha_rows ha_myisam::multi_range_read_info(uint keyno, uint n_ranges, uint keys,
uint *bufsz, uint *flags,
- COST_VECT *cost)
+ Cost_estimate *cost)
{
ds_mrr.init(this, table);
return ds_mrr.dsmrr_info(keyno, n_ranges, keys, bufsz, flags, cost);
=== modified file 'storage/myisam/ha_myisam.h'
--- a/storage/myisam/ha_myisam.h 2011-07-04 00:25:46 +0000
+++ b/storage/myisam/ha_myisam.h 2011-11-08 11:37:54 +0000
@@ -161,9 +161,9 @@ public:
ha_rows multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
void *seq_init_param,
uint n_ranges, uint *bufsz,
- uint *flags, COST_VECT *cost);
+ uint *flags, Cost_estimate *cost);
ha_rows multi_range_read_info(uint keyno, uint n_ranges, uint keys,
- uint *bufsz, uint *flags, COST_VECT *cost);
+ uint *bufsz, uint *flags, Cost_estimate *cost);
/* Index condition pushdown implementation */
Item *idx_cond_push(uint keyno, Item* idx_cond);
=== modified file 'unittest/gunit/CMakeLists.txt'
--- a/unittest/gunit/CMakeLists.txt 2011-10-13 12:33:08 +0000
+++ b/unittest/gunit/CMakeLists.txt 2011-11-08 11:37:54 +0000
@@ -240,6 +240,7 @@ SET(TESTS
sql_list
sql_plist
thread_utils
+ cost_estimate
)
# Add tests (link them with gunit library and the server libraries)
=== added file 'unittest/gunit/cost_estimate-t.cc'
--- a/unittest/gunit/cost_estimate-t.cc 1970-01-01 00:00:00 +0000
+++ b/unittest/gunit/cost_estimate-t.cc 2011-11-08 11:37:54 +0000
@@ -0,0 +1,140 @@
+/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+// First include (the generated) my_config.h, to get correct platform defines,
+// then gtest.h (before any other MySQL headers), to avoid min() macros etc ...
+#include "my_config.h"
+#include <gtest/gtest.h>
+
+#include "handler.h"
+
+namespace {
+
+TEST(CostEstimateTest, Basics)
+{
+ Cost_estimate ce1;
+
+ EXPECT_EQ(0, ce1.total_cost());
+ EXPECT_TRUE(ce1.is_zero());
+
+ const double initial_io_cost= 4.5;
+
+ ce1.add_io(initial_io_cost);
+ EXPECT_FALSE(ce1.is_zero());
+ EXPECT_DOUBLE_EQ(initial_io_cost, ce1.total_cost());
+
+ const double initial_cpu_cost= 3.3;
+ ce1.add_cpu(initial_cpu_cost);
+
+ EXPECT_DOUBLE_EQ(initial_cpu_cost, ce1.get_cpu_cost());
+ EXPECT_DOUBLE_EQ(initial_io_cost, ce1.get_io_cost());
+ EXPECT_DOUBLE_EQ(initial_io_cost + initial_cpu_cost, ce1.total_cost());
+
+ EXPECT_EQ(0, ce1.get_mem_cost());
+ EXPECT_EQ(0, ce1.get_import_cost());
+
+ const double initial_mem_cost= 7;
+ const double initial_import_cost= 11;
+ ce1.add_mem(initial_mem_cost);
+ ce1.add_import(initial_import_cost);
+
+ const double total_initial_cost=
+ initial_io_cost + initial_cpu_cost + initial_import_cost;
+ EXPECT_DOUBLE_EQ(total_initial_cost, ce1.total_cost());
+
+ const double added_io_cost= 1.5;
+ ce1.add_io(added_io_cost);
+ EXPECT_DOUBLE_EQ(initial_io_cost + added_io_cost, ce1.get_io_cost());
+ EXPECT_DOUBLE_EQ(total_initial_cost + added_io_cost, ce1.total_cost());
+
+ EXPECT_FALSE(ce1.is_zero());
+
+ ce1.reset();
+ EXPECT_TRUE(ce1.is_zero());
+
+}
+
+TEST(CostEstimateTest, Operators)
+{
+ Cost_estimate ce_io;
+
+ EXPECT_EQ(0, ce_io.total_cost());
+ EXPECT_TRUE(ce_io.is_zero());
+
+ const double initial_io_cost= 4.5;
+ ce_io.add_io(initial_io_cost);
+ EXPECT_DOUBLE_EQ(initial_io_cost, ce_io.total_cost());
+
+ Cost_estimate ce_cpu;
+ const double initial_cpu_cost= 3.3;
+ ce_cpu.add_cpu(initial_cpu_cost);
+ EXPECT_DOUBLE_EQ(initial_cpu_cost, ce_cpu.total_cost());
+ EXPECT_EQ(0, ce_cpu.get_io_cost());
+
+ // Copy CTOR
+ Cost_estimate ce_copy(ce_io);
+ const double added_io_cost= 1.5;
+ ce_io.add_io(added_io_cost); // should not add to ce_copy
+ EXPECT_DOUBLE_EQ(initial_io_cost + added_io_cost, ce_io.total_cost());
+ EXPECT_DOUBLE_EQ(initial_io_cost, ce_copy.total_cost());
+
+ // operator+=
+ ce_copy+= ce_cpu;
+ EXPECT_DOUBLE_EQ(initial_io_cost + initial_cpu_cost, ce_copy.total_cost());
+
+ // operator+
+ Cost_estimate ce_copy2= ce_io + ce_cpu;
+ const double copy2_totcost=
+ initial_io_cost + added_io_cost + initial_cpu_cost;
+ EXPECT_DOUBLE_EQ(copy2_totcost, ce_copy2.total_cost());
+
+ Cost_estimate ce_mem_import1;
+ const double import1_mem_cost= 3;
+ const double import1_import_cost= 5;
+ ce_mem_import1.add_mem(import1_mem_cost);
+ ce_mem_import1.add_import(import1_import_cost);
+
+ Cost_estimate ce_mem_import2;
+ const double import2_mem_cost= 11;
+ const double import2_import_cost= 13;
+ ce_mem_import2.add_mem(import2_mem_cost);
+ ce_mem_import2.add_import(import2_import_cost);
+
+ // operator+
+ Cost_estimate ce_mi_copy= ce_mem_import1 + ce_mem_import2;
+ EXPECT_DOUBLE_EQ(import1_import_cost + import2_import_cost,
+ ce_mi_copy.total_cost());
+ EXPECT_DOUBLE_EQ(import1_mem_cost + import2_mem_cost,
+ ce_mi_copy.get_mem_cost());
+ EXPECT_DOUBLE_EQ(import1_import_cost + import2_import_cost,
+ ce_mi_copy.get_import_cost());
+
+ // operator+=
+ ce_mi_copy+= ce_mem_import1;
+ EXPECT_DOUBLE_EQ(2*import1_import_cost + import2_import_cost,
+ ce_mi_copy.total_cost());
+ EXPECT_DOUBLE_EQ(2*import1_mem_cost + import2_mem_cost,
+ ce_mi_copy.get_mem_cost());
+ EXPECT_DOUBLE_EQ(2*import1_import_cost + import2_import_cost,
+ ce_mi_copy.get_import_cost());
+
+ // copy assignment
+ Cost_estimate ce_copy3;
+ ce_copy3= ce_copy2;
+ EXPECT_DOUBLE_EQ(copy2_totcost, ce_copy3.total_cost());
+}
+
+
+} //namespace
No bundle (reason: useless for push emails).
| Thread |
|---|
| • bzr push into mysql-trunk branch (jorgen.loland:3479 to 3480) WL#5860 | Jorgen Loland | 11 Nov |