diff options
author | Sergei Golubchik <sergii@pisem.net> | 2011-10-19 21:45:18 +0200 |
---|---|---|
committer | Sergei Golubchik <sergii@pisem.net> | 2011-10-19 21:45:18 +0200 |
commit | 76f0b94bb0b2994d639353530c5b251d0f1a204b (patch) | |
tree | 9ed50628aac34f89a37637bab2fc4915b86b5eb4 /sql/sql_expression_cache.cc | |
parent | 4e46d8e5bff140f2549841167dc4b65a3c0a645d (diff) | |
parent | 5dc1a2231f55bacc9aaf0e24816f3d9c2ee1f21d (diff) | |
download | mariadb-git-76f0b94bb0b2994d639353530c5b251d0f1a204b.tar.gz |
merge with 5.3
sql/sql_insert.cc:
CREATE ... IF NOT EXISTS may do nothing, but
it is still not a failure. don't forget to my_ok it.
******
CREATE ... IF NOT EXISTS may do nothing, but
it is still not a failure. don't forget to my_ok it.
sql/sql_table.cc:
small cleanup
******
small cleanup
Diffstat (limited to 'sql/sql_expression_cache.cc')
-rw-r--r-- | sql/sql_expression_cache.cc | 174 |
1 files changed, 108 insertions, 66 deletions
diff --git a/sql/sql_expression_cache.cc b/sql/sql_expression_cache.cc index d91868ca916..3be6dea7df9 100644 --- a/sql/sql_expression_cache.cc +++ b/sql/sql_expression_cache.cc @@ -1,8 +1,38 @@ +/* Copyright (C) 2010-2011 Monty Program Ab & Oleksandr Byelkin + + 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 */ #include "sql_base.h" #include "sql_select.h" #include "sql_expression_cache.h" +/** + Minimum hit ration to proceed on disk if in memory table overflowed. + hit_rate = hit / (miss + hit); +*/ +#define EXPCACHE_MIN_HIT_RATE_FOR_DISK_TABLE 0.7 +/** + Minimum hit ratio to keep in memory table (do not switch cache off) + hit_rate = hit / (miss + hit); +*/ +#define EXPCACHE_MIN_HIT_RATE_FOR_MEM_TABLE 0.2 +/** + Number of cache miss to check hit ratio (maximum cache performance + impact in the case when the cache is not applicable) +*/ +#define EXPCACHE_CHECK_HIT_RATIO_AFTER 200 + /* Expression cache is used only for caching subqueries now, so its statistic variables we call subquery_cache*. @@ -10,10 +40,10 @@ ulong subquery_cache_miss, subquery_cache_hit; Expression_cache_tmptable::Expression_cache_tmptable(THD *thd, - List<Item*> &dependants, - Item *value) - :cache_table(NULL), table_thd(thd), list(&dependants), val(value), - inited (0) + List<Item> &dependants, + Item *value) + :cache_table(NULL), table_thd(thd), items(dependants), val(value), + hit(0), miss(0), inited (0) { DBUG_ENTER("Expression_cache_tmptable::Expression_cache_tmptable"); DBUG_VOID_RETURN; @@ -21,6 +51,18 @@ Expression_cache_tmptable::Expression_cache_tmptable(THD *thd, /** + Disable cache +*/ + +void Expression_cache_tmptable::disable_cache() +{ + cache_table->file->ha_index_end(); + free_tmp_table(table_thd, cache_table); + cache_table= NULL; +} + + +/** Field enumerator for TABLE::add_tmp_key @param arg reference variable with current field number @@ -47,56 +89,38 @@ static uint field_enumerator(uchar *arg) void Expression_cache_tmptable::init() { - List_iterator<Item*> li(*list); - Item_iterator_ref_list it(li); - Item **item; + List_iterator<Item> li(items); + Item_iterator_list it(li); uint field_counter; DBUG_ENTER("Expression_cache_tmptable::init"); DBUG_ASSERT(!inited); inited= TRUE; cache_table= NULL; - while ((item= li++)) - { - DBUG_ASSERT(item); - if (*item) - { - DBUG_ASSERT((*item)->fixed); - items.push_back((*item)); - } - else - { - /* - This is possible when optimizer already executed this subquery and - optimized out the condition predicate. - */ - li.remove(); - } - } - - if (list->elements == 0) + if (items.elements == 0) { DBUG_PRINT("info", ("All parameters were removed by optimizer.")); DBUG_VOID_RETURN; } + /* add result field */ + items.push_front(val); + cache_table_param.init(); /* dependent items and result */ - cache_table_param.field_count= list->elements + 1; + cache_table_param.field_count= items.elements; /* postpone table creation to index description */ cache_table_param.skip_create_table= 1; - cache_table= NULL; - - items.push_front(val); if (!(cache_table= create_tmp_table(table_thd, &cache_table_param, items, (ORDER*) NULL, - FALSE, FALSE, + FALSE, TRUE, ((table_thd->variables.option_bits | TMP_TABLE_ALL_COLUMNS) & ~TMP_TABLE_FORCE_MYISAM), HA_POS_ERROR, - (char *)"subquery-cache-table"))) + (char *)"subquery-cache-table", + TRUE))) { DBUG_PRINT("error", ("create_tmp_table failed, caching switched off")); DBUG_VOID_RETURN; @@ -108,22 +132,18 @@ void Expression_cache_tmptable::init() goto error; } - /* This list do not contain result field */ - it.open(); - - field_counter=1; + field_counter= 1; if (cache_table->alloc_keys(1) || cache_table->add_tmp_key(0, items.elements - 1, &field_enumerator, (uchar*)&field_counter, TRUE) || ref.tmp_table_index_lookup_init(table_thd, cache_table->key_info, it, - TRUE)) + TRUE, 1 /* skip result field*/)) { DBUG_PRINT("error", ("creating index failed")); goto error; } cache_table->s->keys= 1; - cache_table->s->uniques= 1; ref.null_rejecting= 1; ref.disable_cache= FALSE; ref.has_record= 0; @@ -145,20 +165,19 @@ void Expression_cache_tmptable::init() DBUG_VOID_RETURN; error: - /* switch off cache */ - free_tmp_table(table_thd, cache_table); - cache_table= NULL; + disable_cache(); DBUG_VOID_RETURN; } Expression_cache_tmptable::~Expression_cache_tmptable() { + /* Add accumulated statistics */ + statistic_add(subquery_cache_miss, miss, &LOCK_status); + statistic_add(subquery_cache_hit, hit, &LOCK_status); + if (cache_table) - { - cache_table->file->ha_index_end(); - free_tmp_table(table_thd, cache_table); - } + disable_cache(); } @@ -182,26 +201,28 @@ Expression_cache::result Expression_cache_tmptable::check_value(Item **value) int res; DBUG_ENTER("Expression_cache_tmptable::check_value"); - /* - We defer cache initialization to get item references that are - used at the execution phase. - */ - if (!inited) - init(); - if (cache_table) { DBUG_PRINT("info", ("status: %u has_record %u", (uint)cache_table->status, (uint)ref.has_record)); if ((res= join_read_key2(table_thd, NULL, cache_table, &ref)) == 1) DBUG_RETURN(ERROR); + if (res) { - subquery_cache_miss++; + if (((++miss) == EXPCACHE_CHECK_HIT_RATIO_AFTER) && + ((double)hit / ((double)hit + miss)) < + EXPCACHE_MIN_HIT_RATE_FOR_MEM_TABLE) + { + DBUG_PRINT("info", + ("Early check: hit rate is not so good to keep the cache")); + disable_cache(); + } + DBUG_RETURN(MISS); } - subquery_cache_hit++; + hit++; *value= cached_result; DBUG_RETURN(Expression_cache::HIT); } @@ -239,15 +260,37 @@ my_bool Expression_cache_tmptable::put_value(Item *value) if (table_thd->is_error()) goto err;; - if ((error= cache_table->file->ha_write_row(cache_table->record[0]))) + if ((error= cache_table->file->ha_write_tmp_row(cache_table->record[0]))) { /* create_myisam_from_heap will generate error if needed */ - if (cache_table->file->is_fatal_error(error, HA_CHECK_DUP) && - create_internal_tmp_table_from_heap(table_thd, cache_table, - cache_table_param.start_recinfo, - &cache_table_param.recinfo, - error, 1)) + if (cache_table->file->is_fatal_error(error, HA_CHECK_DUP)) goto err; + else + { + double hit_rate= ((double)hit / ((double)hit + miss)); + DBUG_ASSERT(miss > 0); + if (hit_rate < EXPCACHE_MIN_HIT_RATE_FOR_MEM_TABLE) + { + DBUG_PRINT("info", ("hit rate is not so good to keep the cache")); + disable_cache(); + DBUG_RETURN(FALSE); + } + else if (hit_rate < EXPCACHE_MIN_HIT_RATE_FOR_DISK_TABLE) + { + DBUG_PRINT("info", ("hit rate is not so good to go to disk")); + if (cache_table->file->ha_delete_all_rows() || + cache_table->file->ha_write_tmp_row(cache_table->record[0])) + goto err; + } + else + { + if (create_internal_tmp_table_from_heap(table_thd, cache_table, + cache_table_param.start_recinfo, + &cache_table_param.recinfo, + error, 1)) + goto err; + } + } } cache_table->status= 0; /* cache_table->record contains an existed record */ ref.has_record= TRUE; /* the same as above */ @@ -256,25 +299,24 @@ my_bool Expression_cache_tmptable::put_value(Item *value) DBUG_RETURN(FALSE); err: - cache_table->file->ha_index_end(); - free_tmp_table(table_thd, cache_table); - cache_table= NULL; + disable_cache(); DBUG_RETURN(TRUE); } void Expression_cache_tmptable::print(String *str, enum_query_type query_type) { - List_iterator<Item*> li(*list); - Item **item; + List_iterator<Item> li(items); + Item *item; bool is_first= TRUE; str->append('<'); + li++; // skip result field while ((item= li++)) { if (!is_first) str->append(','); - (*item)->print(str, query_type); + item->print(str, query_type); is_first= FALSE; } str->append('>'); |