summaryrefslogtreecommitdiff
path: root/sql/opt_range.cc
diff options
context:
space:
mode:
authorMichael Widenius <monty@askmonty.org>2011-05-18 19:26:30 +0300
committerMichael Widenius <monty@askmonty.org>2011-05-18 19:26:30 +0300
commit3631146442bc09e5129334774b4bcdf2470a4b27 (patch)
treec812cd2520a8af89c95abf5e6fbec47998908c58 /sql/opt_range.cc
parent5c70f813f3d12974bf67d6ff98c0ff4b9ca71d7d (diff)
downloadmariadb-git-3631146442bc09e5129334774b4bcdf2470a4b27.tar.gz
Original idea from Zardosht Kasheff to add HA_CLUSTERED_INDEX
- Added a lot of code comments - Updated get_best_ror_intersec() to prefer index scan on not clustered keys before clustered keys. - Use HA_CLUSTERED_INDEX to define if one should use HA_MRR_INDEX_ONLY - For test of using index or filesort to resolve ORDER BY, use HA_CLUSTERED_INDEX flag instead of primary_key_is_clustered() - Use HA_TABLE_SCAN_ON_INDEX instead of primary_key_is_clustered() to decide if ALTER TABLE ... ORDER BY will have any effect. sql/ha_partition.h: Added comment with warning for code unsafe to use with multiple storage engines at the same time sql/handler.h: Added HA_CLUSTERED_INDEX. Documented primary_key_is_clustered() sql/opt_range.cc: Added code comments Updated get_best_ror_intersec() to ignore clustered keys. Optimized away cpk_scan_used and one instance of current_thd (Simpler code) Use HA_CLUSTERED_INDEX to define if one should use HA_MRR_INDEX_ONLY sql/sql_select.cc: Changed comment to #ifdef For test of using index or filesort to resolve ORDER BY, use HA_CLUSTERED_INDEX flag instead of primary_key_is_clustered() (Change is smaller than what it looks beause of indentation change) sql/sql_table.cc: Use HA_TABLE_SCAN_ON_INDEX instead of primary_key_is_clustered() to decide if ALTER TABLE ... ORDER BY will have any effect. storage/innobase/handler/ha_innodb.h: Added support for HA_CLUSTERED_INDEX storage/innodb_plugin/handler/ha_innodb.cc: Added support for HA_CLUSTERED_INDEX storage/xtradb/handler/ha_innodb.cc: Added support for HA_CLUSTERED_INDEX
Diffstat (limited to 'sql/opt_range.cc')
-rw-r--r--sql/opt_range.cc54
1 files changed, 43 insertions, 11 deletions
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 102fd881d9f..13afffd6ba9 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -1816,6 +1816,12 @@ QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT()
DBUG_VOID_RETURN;
}
+/*
+ QUICK_INDEX_SORT_SELECT works as follows:
+ - Do index scans, accumulate rowids in the Unique object
+ (Unique will also sort and de-duplicate rowids)
+ - Use rowids from unique to run a disk-ordered sweep
+*/
QUICK_INDEX_SORT_SELECT::QUICK_INDEX_SORT_SELECT(THD *thd_param,
TABLE *table)
@@ -1848,7 +1854,18 @@ QUICK_INDEX_SORT_SELECT::push_quick_back(QUICK_RANGE_SELECT *quick_sel_range)
if (head->file->primary_key_is_clustered() &&
quick_sel_range->index == head->s->primary_key)
{
- /* A quick_select over a clustered primary key is handled specifically */
+ /*
+ A quick_select over a clustered primary key is handled specifically
+ Here we assume:
+ - PK columns are included in any other merged index
+ - Scan on the PK is disk-ordered.
+ (not meeting #2 will only cause performance degradation)
+
+ We could treat clustered PK as any other index, but that would
+ be inefficient. There is no point in doing scan on
+ CPK, remembering the rowid, then making rnd_pos() call with
+ that rowid.
+ */
pk_quick_select= quick_sel_range;
DBUG_RETURN(0);
}
@@ -4298,11 +4315,19 @@ double get_sweep_read_cost(const PARAM *param, ha_rows records)
DBUG_ENTER("get_sweep_read_cost");
if (param->table->file->primary_key_is_clustered())
{
+ /*
+ We are using the primary key to find the rows.
+ Calculate the cost for this.
+ */
result= param->table->file->read_time(param->table->s->primary_key,
(uint)records, records);
}
else
{
+ /*
+ Rows will be retreived with rnd_pos(). Caluclate the expected
+ cost for this.
+ */
double n_blocks=
ceil(ulonglong2double(param->table->file->stats.data_file_length) /
IO_SIZE);
@@ -5013,7 +5038,7 @@ bool prepare_search_best_index_intersect(PARAM *param,
if ((*index_scan)->keynr == table->s->primary_key)
{
common->cpk_scan= cpk_scan= *index_scan;
- break;
+ break;
}
}
}
@@ -6187,7 +6212,6 @@ TRP_ROR_INTERSECT *get_best_ror_intersect(const PARAM *param, SEL_TREE *tree,
ROR_SCAN_INFO **cur_ror_scan;
ROR_SCAN_INFO *cpk_scan= NULL;
uint cpk_no;
- bool cpk_scan_used= FALSE;
if (!(tree->ror_scans= (ROR_SCAN_INFO**)alloc_root(param->mem_root,
sizeof(ROR_SCAN_INFO*)*
@@ -6199,11 +6223,20 @@ TRP_ROR_INTERSECT *get_best_ror_intersect(const PARAM *param, SEL_TREE *tree,
for (idx= 0, cur_ror_scan= tree->ror_scans; idx < param->keys; idx++)
{
ROR_SCAN_INFO *scan;
+ uint key_no;
if (!tree->ror_scans_map.is_set(idx))
continue;
+ key_no= param->real_keynr[idx];
+ if (key_no != cpk_no &&
+ param->table->file->index_flags(key_no,0,0) & HA_CLUSTERED_INDEX)
+ {
+ /* Ignore clustering keys */
+ tree->n_ror_scans--;
+ continue;
+ }
if (!(scan= make_ror_scan(param, idx, tree->keys[idx])))
return NULL;
- if (param->real_keynr[idx] == cpk_no)
+ if (key_no == cpk_no)
{
cpk_scan= scan;
tree->n_ror_scans--;
@@ -6289,15 +6322,14 @@ TRP_ROR_INTERSECT *get_best_ror_intersect(const PARAM *param, SEL_TREE *tree,
{
if (ror_intersect_add(intersect, cpk_scan, TRUE) &&
(intersect->total_cost < min_cost))
- {
- cpk_scan_used= TRUE;
intersect_best= intersect; //just set pointer here
- }
}
+ else
+ cpk_scan= 0; // Don't use cpk_scan
/* Ok, return ROR-intersect plan if we have found one */
TRP_ROR_INTERSECT *trp= NULL;
- if (min_cost < read_time && (cpk_scan_used || best_num > 1))
+ if (min_cost < read_time && (cpk_scan || best_num > 1))
{
if (!(trp= new (param->mem_root) TRP_ROR_INTERSECT))
DBUG_RETURN(trp);
@@ -6316,7 +6348,7 @@ TRP_ROR_INTERSECT *get_best_ror_intersect(const PARAM *param, SEL_TREE *tree,
set_if_smaller(param->table->quick_condition_rows, best_rows);
trp->records= best_rows;
trp->index_scan_costs= intersect_best->index_scan_costs;
- trp->cpk_scan= cpk_scan_used? cpk_scan: NULL;
+ trp->cpk_scan= cpk_scan;
DBUG_PRINT("info", ("Returning non-covering ROR-intersect plan:"
"cost %g, records %lu",
trp->read_cost, (ulong) trp->records));
@@ -9511,10 +9543,10 @@ ha_rows check_quick_select(PARAM *param, uint idx, bool index_only,
bool pk_is_clustered= file->primary_key_is_clustered();
if (index_only &&
(file->index_flags(keynr, param->max_key_part, 1) & HA_KEYREAD_ONLY) &&
- !(pk_is_clustered && keynr == param->table->s->primary_key))
+ !(file->index_flags(keynr, param->max_key_part, 1) & HA_CLUSTERED_INDEX))
*mrr_flags |= HA_MRR_INDEX_ONLY;
- if (current_thd->lex->sql_command != SQLCOM_SELECT)
+ if (param->thd->lex->sql_command != SQLCOM_SELECT)
*mrr_flags |= HA_MRR_USE_DEFAULT_IMPL;
*bufsize= param->thd->variables.mrr_buff_size;