mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 12:02:42 +01:00
ef4c0f68d1
use limit efficiently Bug #36569: UPDATE ... WHERE ... ORDER BY... always does a filesort even if not required Also two bugs reported after QA review (before the commit of bugs above to public trees, no documentation needed): Bug #53737: Performance regressions after applying patch for bug 36569 Bug #53742: UPDATEs have no effect after applying patch for bug 36569 Execution of single-table UPDATE and DELETE statements did not use the same optimizer as was used in the compilation of SELECT statements. Instead, it had an optimizer of its own that did not take into account that you can omit sorting by retrieving rows using an index. Extra optimization has been added: when applicable, single-table UPDATE/DELETE statements use an existing index instead of filesort. A corresponding SELECT query would do the former. Also handling of the DESC ordering expression has been added when reverse index scan is applicable. From now on most single table UPDATE and DELETE statements show the same disk access patterns as the corresponding SELECT query. We verify this by comparing the result of SHOW STATUS LIKE 'Sort% Currently the get_index_for_order function a) checks quick select index (if any) for compatibility with the ORDER expression list or b) chooses the cheapest available compatible index, but only if the index scan is cheaper than filesort. Second way is implemented by the new test_if_cheaper_ordering function (extracted part the test_if_skip_sort_order()). mysql-test/r/log_state.result: Updated result for optimized query, bug #36569. mysql-test/r/single_delete_update.result: Test case for bug #30584, bug #36569 and bug #53742. mysql-test/r/update.result: Updated result for optimized query, bug #30584. Note: "Handler_read_last 1" omitted, see bug 52312: lost Handler_read_last status variable. mysql-test/t/single_delete_update.test: Test case for bug #30584, bug #36569 and bug #53742. sql/opt_range.cc: Bug #30584, bug #36569: UPDATE/DELETE ... WHERE ... ORDER BY... always does a filesort even if not required * get_index_for_order() has been rewritten entirely and moved to sql_select.cc New QUICK_RANGE_SELECT::make_reverse method has been added. sql/opt_range.h: Bug #30584, bug #36569: UPDATE/DELETE ... WHERE ... ORDER BY... always does a filesort even if not required * get_index_for_order() has been rewritten entirely and moved to sql_select.cc New functions: * QUICK_SELECT_I::make_reverse() * SQL_SELECT::set_quick() sql/records.cc: Bug #30584, bug #36569: UPDATE/DELETE ... WHERE ... ORDER BY... always does a filesort even if not required * init_read_record_idx() has been modified to allow reverse index scan New functions: * rr_index_last() * rr_index_desc() sql/records.h: Bug #30584, bug #36569: UPDATE/DELETE ... WHERE ... ORDER BY... always does a filesort even if not required init_read_record_idx() has been modified to allow reverse index scan sql/sql_delete.cc: Bug #30584, bug #36569: UPDATE/DELETE ... WHERE ... ORDER BY... always does a filesort even if not required mysql_delete: an optimization has been added to skip unnecessary sorting with ORDER BY clause where select result ordering is acceptable. sql/sql_select.cc: Bug #30584, bug #36569, bug #53737, bug #53742: UPDATE/DELETE ... WHERE ... ORDER BY... always does a filesort even if not required The const_expression_in_where function has been modified to accept both Item and Field pointers. New functions: * get_index_for_order() * test_if_cheaper_ordering() has been extracted from test_if_skip_sort_order() to share with get_index_for_order() * simple_remove_const() sql/sql_select.h: Bug #30584, bug #36569: UPDATE/DELETE ... WHERE ... ORDER BY... always does a filesort even if not required New functions: * test_if_cheaper_ordering() * simple_remove_const() * get_index_for_order() sql/sql_update.cc: Bug #30584, bug #36569: UPDATE/DELETE ... WHERE ... ORDER BY... always does a filesort even if not required mysql_update: an optimization has been added to skip unnecessary sorting with ORDER BY clause where a select result ordering is acceptable. sql/table.cc: Bug #30584, bug #36569: UPDATE/DELETE ... WHERE ... ORDER BY... always does a filesort even if not required New functions: * TABLE::update_const_key_parts() * is_simple_order() sql/table.h: Bug #30584, bug #36569: UPDATE/DELETE ... WHERE ... ORDER BY... always does a filesort even if not required New functions: * TABLE::update_const_key_parts() * is_simple_order()
79 lines
2.5 KiB
C++
79 lines
2.5 KiB
C++
#ifndef SQL_RECORDS_H
|
|
#define SQL_RECORDS_H
|
|
/* Copyright (C) 2008 Sun/MySQL
|
|
|
|
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 */
|
|
|
|
#ifdef USE_PRAGMA_INTERFACE
|
|
#pragma interface /* gcc class implementation */
|
|
#endif
|
|
#include <my_global.h> /* for uint typedefs */
|
|
|
|
struct st_join_table;
|
|
class handler;
|
|
struct TABLE;
|
|
class THD;
|
|
class SQL_SELECT;
|
|
|
|
/**
|
|
A context for reading through a single table using a chosen access method:
|
|
index read, scan, etc, use of cache, etc.
|
|
|
|
Use by:
|
|
READ_RECORD read_record;
|
|
init_read_record(&read_record, ...);
|
|
while (read_record.read_record())
|
|
{
|
|
...
|
|
}
|
|
end_read_record();
|
|
*/
|
|
|
|
struct READ_RECORD
|
|
{
|
|
typedef int (*Read_func)(READ_RECORD*);
|
|
typedef void (*Unlock_row_func)(st_join_table *);
|
|
typedef int (*Setup_func)(struct st_join_table*);
|
|
|
|
TABLE *table; /* Head-form */
|
|
handler *file;
|
|
TABLE **forms; /* head and ref forms */
|
|
Unlock_row_func unlock_row;
|
|
Read_func read_record;
|
|
THD *thd;
|
|
SQL_SELECT *select;
|
|
uint cache_records;
|
|
uint ref_length,struct_length,reclength,rec_cache_size,error_offset;
|
|
uint index;
|
|
uchar *ref_pos; /* pointer to form->refpos */
|
|
uchar *record;
|
|
uchar *rec_buf; /* to read field values after filesort */
|
|
uchar *cache,*cache_pos,*cache_end,*read_positions;
|
|
struct st_io_cache *io_cache;
|
|
bool print_error, ignore_not_found_rows;
|
|
|
|
public:
|
|
READ_RECORD() {}
|
|
};
|
|
|
|
void init_read_record(READ_RECORD *info, THD *thd, TABLE *reg_form,
|
|
SQL_SELECT *select, int use_record_cache,
|
|
bool print_errors, bool disable_rr_cache);
|
|
void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table,
|
|
bool print_error, uint idx, bool reverse);
|
|
void end_read_record(READ_RECORD *info);
|
|
|
|
void rr_unlock_row(st_join_table *tab);
|
|
|
|
#endif /* SQL_RECORDS_H */
|