From e13405a79f1f5c69809e5d1483dc1da8a6bc3c48 Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Fri, 9 Jul 2010 01:09:31 +0200 Subject: [PATCH 1/3] Bug#52455: Subpar INSERT ON DUPLICATE KEY UPDATE performance with many partitions The handler function for reading one row from a specific index was not optimized in the partitioning handler since it used the default implementation. No test case since it is performance only, verified by hand. --- sql/ha_partition.cc | 52 +++++++++++++++++++++++++++++++++++++++++++++ sql/ha_partition.h | 9 ++++++++ 2 files changed, 61 insertions(+) diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 60722f0100e..a87c7fbf7b8 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -4219,6 +4219,58 @@ int ha_partition::index_read_last_map(uchar *buf, const uchar *key, } +/* + Optimization of the default implementation to take advantage of dynamic + partition pruning. +*/ +int ha_partition::index_read_idx_map(uchar *buf, uint index, + const uchar *key, + key_part_map keypart_map, + enum ha_rkey_function find_flag) +{ + int error= HA_ERR_KEY_NOT_FOUND; + DBUG_ENTER("ha_partition::index_read_idx_map"); + + if (find_flag == HA_READ_KEY_EXACT) + { + uint part; + m_start_key.key= key; + m_start_key.keypart_map= keypart_map; + m_start_key.flag= find_flag; + m_start_key.length= calculate_key_len(table, index, m_start_key.key, + m_start_key.keypart_map); + + get_partition_set(table, buf, index, &m_start_key, &m_part_spec); + + /* How can it be more than one partition with the current use? */ + DBUG_ASSERT(m_part_spec.start_part == m_part_spec.end_part); + + for (part= m_part_spec.start_part; part <= m_part_spec.end_part; part++) + { + if (bitmap_is_set(&(m_part_info->used_partitions), part)) + { + error= m_file[part]->index_read_idx_map(buf, index, key, + keypart_map, find_flag); + if (error != HA_ERR_KEY_NOT_FOUND && + error != HA_ERR_END_OF_FILE) + break; + } + } + } + else + { + /* + If not only used with READ_EXACT, we should investigate if possible + to optimize for other find_flag's as well. + */ + DBUG_ASSERT(0); + /* fall back on the default implementation */ + error= handler::index_read_idx_map(buf, index, key, keypart_map, find_flag); + } + DBUG_RETURN(error); +} + + /* Read next record in a forward index scan diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 9f6d9e0a5ba..d8872d37a09 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -448,6 +448,15 @@ public: virtual int index_init(uint idx, bool sorted); virtual int index_end(); + /** + @breif + Positions an index cursor to the index specified in the hanlde. Fetches the + row if available. If the key value is null, begin at first key of the + index. + */ + virtual int index_read_idx_map(uchar *buf, uint index, const uchar *key, + key_part_map keypart_map, + enum ha_rkey_function find_flag); /* These methods are used to jump to next or previous entry in the index scan. There are also methods to jump to first and last entry. From 9414aee2259a9a52c0d104a9b7bdafeaca1ad50f Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Fri, 9 Jul 2010 13:15:26 +0200 Subject: [PATCH 2/3] Bug#52517: Regression in ROW level replication performance with partitions In bug-28430 HA_PRIMARY_KEY_REQUIRED_FOR_POSITION was disabled in the partitioning engine in the first patch, That bug was later fixed a second time, but that flag was not removed. No need to disable this flag, as it leads to bad choise in row replication. --- sql/ha_partition.h | 6 +----- sql/handler.h | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 9f6d9e0a5ba..351d3d6b247 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -53,8 +53,7 @@ typedef struct st_ha_data_partition HA_CAN_FULLTEXT | \ HA_DUPLICATE_POS | \ HA_CAN_SQL_HANDLER | \ - HA_CAN_INSERT_DELAYED | \ - HA_PRIMARY_KEY_REQUIRED_FOR_POSITION) + HA_CAN_INSERT_DELAYED) class ha_partition :public handler { private: @@ -766,9 +765,6 @@ public: HA_PRIMARY_KEY_REQUIRED_FOR_POSITION: Does the storage engine need a PK for position? - Used with hidden primary key in InnoDB. - Hidden primary keys cannot be supported by partitioning, since the - partitioning expressions columns must be a part of the primary key. (InnoDB) HA_FILE_BASED is always set for partition handler since we use a diff --git a/sql/handler.h b/sql/handler.h index d9dfd4f0707..3c7cba747fa 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -93,7 +93,10 @@ #define HA_PRIMARY_KEY_IN_READ_INDEX (1 << 15) /* If HA_PRIMARY_KEY_REQUIRED_FOR_POSITION is set, it means that to position() - uses a primary key. Without primary key, we can't call position(). + uses a primary key given by the record argument. + Without primary key, we can't call position(). + If not set, the position is returned as the current rows position + regardless of what argument is given. */ #define HA_PRIMARY_KEY_REQUIRED_FOR_POSITION (1 << 16) #define HA_CAN_RTREEKEYS (1 << 17) @@ -1446,10 +1449,9 @@ public: virtual int rnd_next(uchar *buf)=0; virtual int rnd_pos(uchar * buf, uchar *pos)=0; /** - One has to use this method when to find - random position by record as the plain - position() call doesn't work for some - handlers for random position. + This function only works for handlers having + HA_PRIMARY_KEY_REQUIRED_FOR_POSITION set. + It will return the row with the PK given in the record argument. */ virtual int rnd_pos_by_record(uchar *record) { @@ -1467,6 +1469,12 @@ public: { return HA_ERR_WRONG_COMMAND; } virtual ha_rows records_in_range(uint inx, key_range *min_key, key_range *max_key) { return (ha_rows) 10; } + /* + If HA_PRIMARY_KEY_REQUIRED_FOR_POSITION is set, then it sets ref + (reference to the row, aka position, with the primary key given in + the record). + Otherwise it set ref to the current row. + */ virtual void position(const uchar *record)=0; virtual int info(uint)=0; // see my_base.h for full description virtual void get_dynamic_partition_info(PARTITION_INFO *stat_info, From 147963007b9fd3fd84e79f81cfca207c75acf6cc Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Fri, 9 Jul 2010 09:51:21 -0300 Subject: [PATCH 3/3] Remove AC_LANG_WERROR, it causes trouble earlier versions of autoconf and is not strictly needed for now. --- config/ac-macros/maintainer.m4 | 2 -- 1 file changed, 2 deletions(-) diff --git a/config/ac-macros/maintainer.m4 b/config/ac-macros/maintainer.m4 index 6aa1d166f2a..1b7df75d6f7 100644 --- a/config/ac-macros/maintainer.m4 +++ b/config/ac-macros/maintainer.m4 @@ -27,7 +27,6 @@ AC_DEFUN([MY_MAINTAINER_MODE_WARNINGS], [ AC_MSG_CHECKING([whether to use C warning options ${C_WARNINGS}]) AC_LANG_PUSH(C) CFLAGS="$CFLAGS ${C_WARNINGS}" - AC_LANG_WERROR AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], [myac_c_warning_flags=yes], [myac_c_warning_flags=no]) AC_LANG_POP() @@ -41,7 +40,6 @@ AC_DEFUN([MY_MAINTAINER_MODE_WARNINGS], [ AC_MSG_CHECKING([whether to use C++ warning options ${CXX_WARNINGS}]) AC_LANG_PUSH(C++) CXXFLAGS="$CXXFLAGS ${CXX_WARNINGS}" - AC_LANG_WERROR AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], [myac_cxx_warning_flags=yes], [myac_cxx_warning_flags=no]) AC_LANG_POP()