From: Ole John Aske Date: February 9 2011 10:05am Subject: bzr commit into mysql-trunk branch (ole.john.aske:3622) Bug#57601 List-Archive: http://lists.mysql.com/commits/130818 X-Bug: 57601 Message-Id: <20110209100553.410F0223@fimafeng09.norway.sun.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============6126771716535053368==" --===============6126771716535053368== 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:05:47 +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:05:47 +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:05:47 +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:05:47 +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:05:47 +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 --===============6126771716535053368== 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\ # oi8sxn34qwtyyhsv # target_branch: file:///net/fimafeng09/export/home/tmp/oleja/mysql\ # /mysql-trunk/ # testament_sha1: e6d40d05fa21ee4e527c97d81d5ff50569a884d9 # timestamp: 2011-02-09 11:05:53 +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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 --===============6126771716535053368==--