From: Ole John Aske Date: February 9 2011 10:01am Subject: bzr commit into mysql-trunk branch (ole.john.aske:3622) Bug#57601 List-Archive: http://lists.mysql.com/commits/130816 X-Bug: 57601 Message-Id: <20110209100108.82A87223@fimafeng09.norway.sun.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============6972937380733247490==" --===============6972937380733247490== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///net/fimafeng09/export/home/tmp/oleja/mysql/mysql-trunk/ based on revid:georgi.kodinov@stripped 3622 Ole John Aske 2011-02-09 Fix for bug#57601 'Optimizer is overly eager to request ordered access.' Previous fix has been rebased from mysql-5.1 to mysql-trunk. The essential part of this fix is: 1) Ensure that JOIN_TAB::sorted is set, and QUICK_RANGE_SELECT::mrr_flags contains 'HA_MRR_SORTED' only iff strict ordering is required from the handler - Either as a result of the query itself specifying ORDER/GROUP BY, or usage of a QUICK access method which require the sources to be ordered (Typical if its internals use ::ha_index_first, _last, _next, _prev) 2) Change calls to handler::ha_index_init() to take its 'sorted' argument either directly from JOIN_TAB::sorted or from mrr_flags containing HA_MRR_SORTED. In order to implement this, QUICK_SELECT_I::need_sorted_output() had to be extended to take a 'bool sort' argument: Where 'sort==false' will enable us to turn off requirement that a QUICK_SELECT_I access method should deliver rows in sorted order. (Similar logic already exists for 'non-quick' access methods.) NOTE: QUICK_SELECT_I::need_sorted_output(sort==false) is only regarded as a hint and the different QUICK_SELECT_I methods may still request sorted order from the handler if required by their internals. Furthermore the function 'disable_sorted_access(JOIN_TAB* join_tab)' has been introduced which collect all the logic for turning of sort requirement. @ mysql-test/r/innodb_mysql_lock2.result Accept changed result order for this (unordered) result set. @ mysql-test/r/partition.result Accept changed result order for this (unordered) result set. @ sql/opt_range.cc Correcly set, and use, HA_MRR_SORTED in order to only request sorted access iff it is required either due to optimizer using ::need_sorted_output(), or the internals of the quick access needing ordered access itself. Also added mrr_flags and its mrr relatives to C'tor initializer list. And fixed an issue with missing 'delete quick' + return in case get_quick_select() failed. modified: mysql-test/r/innodb_mysql_lock2.result mysql-test/r/partition.result sql/opt_range.cc sql/opt_range.h sql/sql_select.cc === modified file 'mysql-test/r/innodb_mysql_lock2.result' --- a/mysql-test/r/innodb_mysql_lock2.result 2010-07-19 16:09:51 +0000 +++ b/mysql-test/r/innodb_mysql_lock2.result 2011-02-09 10:01:02 +0000 @@ -605,11 +605,11 @@ begin; # Acquire SR metadata lock on t1. select * from t1; i +4 1 +5 2 3 -4 -5 # Switching to connection 'con1'. # Sending: alter table t1 rebuild partition p0; === modified file 'mysql-test/r/partition.result' --- a/mysql-test/r/partition.result 2011-01-10 16:37:47 +0000 +++ b/mysql-test/r/partition.result 2011-02-09 10:01:02 +0000 @@ -1725,9 +1725,9 @@ insert into t1 values (18446744073709551 (18446744073709551613), (18446744073709551612); select * from t1; a +18446744073709551614 18446744073709551612 18446744073709551613 -18446744073709551614 18446744073709551615 select * from t1 where a = 18446744073709551615; a @@ -1735,9 +1735,9 @@ a delete from t1 where a = 18446744073709551615; select * from t1; a +18446744073709551614 18446744073709551612 18446744073709551613 -18446744073709551614 drop table t1; CREATE TABLE t1 ( num int(11) NOT NULL, cs int(11) NOT NULL) === modified file 'sql/opt_range.cc' --- a/sql/opt_range.cc 2010-12-29 00:38:59 +0000 +++ b/sql/opt_range.cc 2011-02-09 10:01:02 +0000 @@ -1178,7 +1178,9 @@ QUICK_SELECT_I::QUICK_SELECT_I() QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(THD *thd, TABLE *table, uint key_nr, bool no_alloc, MEM_ROOT *parent_alloc, bool *create_error) - :free_file(0),cur_range(NULL),last_range(0),dont_free(0) + :free_file(0),cur_range(NULL),last_range(0), + mrr_flags(0),mrr_buf_size(0),mrr_buf_desc(NULL), + dont_free(0) { my_bitmap_map *bitmap; DBUG_ENTER("QUICK_RANGE_SELECT::QUICK_RANGE_SELECT"); @@ -1191,7 +1193,6 @@ QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(T /* 'thd' is not accessible in QUICK_RANGE_SELECT::reset(). */ mrr_buf_size= thd->variables.read_rnd_buff_size; - mrr_buf_desc= NULL; if (!no_alloc && !parent_alloc) { @@ -1219,17 +1220,24 @@ QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(T } -void QUICK_RANGE_SELECT::need_sorted_output() +void QUICK_RANGE_SELECT::need_sorted_output(bool sort) { - if (!(mrr_flags & HA_MRR_SORTED)) + if (sort) { - /* - Native implementation can't produce sorted output. We'll have to - switch to default - */ - mrr_flags |= HA_MRR_USE_DEFAULT_IMPL; + if (!(mrr_flags & HA_MRR_SORTED)) + { + /* + Native implementation can't produce sorted output. We'll have to + switch to default + */ + mrr_flags |= HA_MRR_USE_DEFAULT_IMPL; + } + mrr_flags |= HA_MRR_SORTED; + } + else + { + mrr_flags &= ~HA_MRR_SORTED; } - mrr_flags |= HA_MRR_SORTED; } @@ -8705,7 +8713,8 @@ int QUICK_RANGE_SELECT::reset() { if (in_ror_merged_scan) head->column_bitmaps_set_no_signal(&column_bitmap, &column_bitmap); - if ((error= file->ha_index_init(index,1))) + bool sorted= (mrr_flags & HA_MRR_SORTED); + if ((error= file->ha_index_init(index,sorted))) DBUG_RETURN(error); } @@ -8980,10 +8989,11 @@ int QUICK_RANGE_SELECT::get_next_prefix( last_range->make_min_endpoint(&start_key, prefix_length, keypart_map); last_range->make_max_endpoint(&end_key, prefix_length, keypart_map); + bool sorted= (mrr_flags & HA_MRR_SORTED); result= file->read_range_first(last_range->min_keypart_map ? &start_key : 0, last_range->max_keypart_map ? &end_key : 0, test(last_range->flag & EQ_RANGE), - TRUE); + sorted); if (last_range->flag == (UNIQUE_RANGE | EQ_RANGE)) last_range= 0; // Stop searching @@ -9095,6 +9105,7 @@ QUICK_SELECT_DESC::QUICK_SELECT_DESC(QUI */ mrr_buf_desc= NULL; mrr_flags |= HA_MRR_USE_DEFAULT_IMPL; + mrr_flags |= HA_MRR_SORTED; // 'sorted' as internals use index_last/_prev mrr_buf_size= 0; @@ -10575,12 +10586,19 @@ TRP_GROUP_MIN_MAX::make_quick(PARAM *par if (quick_prefix_records == HA_POS_ERROR) quick->quick_prefix_select= NULL; /* Can't construct a quick select. */ else + { /* Make a QUICK_RANGE_SELECT to be used for group prefix retrieval. */ quick->quick_prefix_select= get_quick_select(param, param_idx, index_tree, - HA_MRR_USE_DEFAULT_IMPL, 0, + HA_MRR_USE_DEFAULT_IMPL | HA_MRR_SORTED, + 0, &quick->alloc); - + if (!quick->quick_prefix_select) + { + delete quick; + DBUG_RETURN(NULL); + } + } /* Extract the SEL_ARG subtree that contains only ranges for the MIN/MAX attribute, and create an array of QUICK_RANGES to be used by the @@ -10976,7 +10994,11 @@ int QUICK_GROUP_MIN_MAX_SELECT::reset(vo DBUG_ENTER("QUICK_GROUP_MIN_MAX_SELECT::reset"); head->set_keyread(TRUE); /* We need only the key attributes */ - if ((result= file->ha_index_init(index,1))) + + // Request ordered index access as usage of ::index_last(), ::index_first() + // within QUICK_GROUP_MIN_MAX_SELECT depends on it. + bool sorted= true; + if ((result= file->ha_index_init(index,sorted))) DBUG_RETURN(result); if (quick_prefix_select && quick_prefix_select->reset()) DBUG_RETURN(1); === modified file 'sql/opt_range.h' --- a/sql/opt_range.h 2010-12-17 12:58:04 +0000 +++ b/sql/opt_range.h 2011-02-09 10:01:02 +0000 @@ -285,11 +285,15 @@ public: virtual bool clustered_pk_range() { return false; } /* - Request that this quick select produces sorted output. Not all quick - selects can do it, the caller is responsible for calling this function - only for those quick selects that can. + Request that this quick select produces sorted output if 'sort==true'. + Not all quick selects can provide sorted output, the caller is responsible + for calling this function only for those quick selects that can. + Caller is allowed to later cancel its sorted request by setting + 'sort==false'. However, the implementation is allowed to provide sorted + output even in this case if benificial, or required by implementation + internals. */ - virtual void need_sorted_output() = 0; + virtual void need_sorted_output(bool sort) = 0; enum { QS_TYPE_RANGE = 0, QS_TYPE_INDEX_MERGE = 1, @@ -399,7 +403,7 @@ uint quick_range_seq_next(range_seq_t rs /* Quick select that does a range scan on a single key. The records are - returned in key order. + returned in key order if ::need_sorted_output(true) has been called. */ class QUICK_RANGE_SELECT : public QUICK_SELECT_I { @@ -465,7 +469,7 @@ public: MEM_ROOT *parent_alloc, bool *create_error); ~QUICK_RANGE_SELECT(); - void need_sorted_output(); + void need_sorted_output(bool sort); int init(); int reset(void); int get_next(); @@ -569,7 +573,7 @@ public: ~QUICK_INDEX_MERGE_SELECT(); int init(); - void need_sorted_output() { DBUG_ASSERT(0); /* Can't do it */ } + void need_sorted_output(bool sort) { DBUG_ASSERT(!sort); /* Can't do it */ } int reset(void); int get_next(); bool reverse_sorted() { return false; } @@ -647,7 +651,7 @@ public: ~QUICK_ROR_INTERSECT_SELECT(); int init(); - void need_sorted_output() { DBUG_ASSERT(0); /* Can't do it */ } + void need_sorted_output(bool sort) { DBUG_ASSERT(!sort); /* Can't do it */ } int reset(void); int get_next(); bool reverse_sorted() { return false; } @@ -718,7 +722,7 @@ public: ~QUICK_ROR_UNION_SELECT(); int init(); - void need_sorted_output() { DBUG_ASSERT(0); /* Can't do it */ } + void need_sorted_output(bool sort) { DBUG_ASSERT(!sort); /* Can't do it */ } int reset(void); int get_next(); bool reverse_sorted() { return false; } @@ -860,7 +864,7 @@ public: void adjust_prefix_ranges(); bool alloc_buffers(); int init(); - void need_sorted_output() { /* always do it */ } + void need_sorted_output(bool sort) { /* always do it */ } int reset(); int get_next(); bool reverse_sorted() { return false; } === modified file 'sql/sql_select.cc' --- a/sql/sql_select.cc 2011-02-08 15:54:12 +0000 +++ b/sql/sql_select.cc 2011-02-09 10:01:02 +0000 @@ -1463,7 +1463,7 @@ bool setup_semijoin_dups_elimination(JOI output is not supported. */ if (tab->select && tab->select->quick) - tab->select->quick->need_sorted_output(); + tab->select->quick->need_sorted_output(true); /* Calculate key length */ keylen= 0; @@ -2735,6 +2735,23 @@ JOIN::save_join_tab() /** + There may be a pending 'sorted' request on the specified + 'join_tab' which we now has decided we can ignore. +*/ +static void +disable_sorted_access(JOIN_TAB* join_tab) +{ + DBUG_ENTER("disable_sorted_access"); + join_tab->sorted= 0; + if (join_tab->select && join_tab->select->quick) + { +// join_tab->select->quick->need_sorted_output(false); + } + DBUG_VOID_RETURN; +} + + +/** Exec select. @todo @@ -2913,7 +2930,7 @@ JOIN::exec() curr_join->const_tables != curr_join->tables && curr_join->best_positions[curr_join->const_tables].sj_strategy != SJ_OPT_LOOSE_SCAN) - curr_join->join_tab[curr_join->const_tables].sorted= 0; + disable_sorted_access(&curr_join->join_tab[curr_join->const_tables]); if ((tmp_error= do_select(curr_join, (List *) 0, curr_tmp_table, 0))) { error= tmp_error; @@ -3079,7 +3096,7 @@ JOIN::exec() curr_join->group_list= 0; if (!curr_join->sort_and_group && curr_join->const_tables != curr_join->tables) - curr_join->join_tab[curr_join->const_tables].sorted= 0; + disable_sorted_access(&curr_join->join_tab[curr_join->const_tables]); if (setup_sum_funcs(curr_join->thd, curr_join->sum_funcs) || (tmp_error= do_select(curr_join, (List *) 0, curr_tmp_table, 0))) @@ -11122,7 +11139,7 @@ make_join_readinfo(JOIN *join, ulonglong { uint i, jcl; bool statistics= test(!(join->select_options & SELECT_DESCRIBE)); - bool sorted= 1; + bool sorted= (join->order || join->group_list); uint first_sjm_table= MAX_TABLES; uint last_sjm_table= MAX_TABLES; DBUG_ENTER("make_join_readinfo"); @@ -18120,6 +18137,7 @@ join_read_key2(JOIN_TAB *tab, TABLE *tab int error; if (!table->file->inited) { + DBUG_ASSERT(!tab->sorted); // Don't expect sort req. for single row. table->file->ha_index_init(table_ref->key, tab->sorted); } @@ -18429,7 +18447,7 @@ join_read_last(JOIN_TAB *tab) tab->read_record.index=tab->index; tab->read_record.record=table->record[0]; if (!table->file->inited) - table->file->ha_index_init(tab->index, 1); + table->file->ha_index_init(tab->index, tab->sorted); if ((error= tab->table->file->ha_index_last(tab->table->record[0]))) return report_error(table, error); return 0; @@ -18453,7 +18471,7 @@ join_ft_read_first(JOIN_TAB *tab) TABLE *table= tab->table; if (!table->file->inited) - table->file->ha_index_init(tab->ref.key, 1); + table->file->ha_index_init(tab->ref.key, tab->sorted); table->file->ft_init(); if ((error= table->file->ft_read(table->record[0]))) @@ -20221,7 +20239,7 @@ check_reverse_order: } } else if (select && select->quick) - select->quick->need_sorted_output(); + select->quick->need_sorted_output(true); } // QEP has been modified --===============6972937380733247490== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/ole.john.aske@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: ole.john.aske@stripped\ # war5d5h2ftu3v03e # target_branch: file:///net/fimafeng09/export/home/tmp/oleja/mysql\ # /mysql-trunk/ # testament_sha1: 2e1c4811eeef32fe3e0bd010dfc416e045459f46 # timestamp: 2011-02-09 11:01:08 +0100 # source_branch: file:///net/fimafeng09/export/home/tmp/oleja/mysql\ # /mysql-5.5/ # base_revision_id: georgi.kodinov@stripped\ # vtp229shgu2phapt # # Begin bundle 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 --===============6972937380733247490==--