From ba3a5c1d4df1c5fb4c0a54b59211f80e525126c9 Mon Sep 17 00:00:00 2001 From: "hope.lb" Date: Wed, 13 Oct 2021 17:49:40 +0800 Subject: [PATCH] [Optimize] Traverse the used partitions instead of all partitions Description ----------- In innobase handler for partitioned table codes, there exist several places where the server traverses all partitions like ha_innopart::store_lock(), ha_innopart::external_lock() and ha_innopart::clear_blob_heaps(). The partitions not used in the query are also traversed, which is unnecessary and a waste and loss to performance. Fix --- Traverse the used partitions instead of all partitions at above mentioned places. Effect ------ We evaluate performance improvement by sysbench oltp_point_select.lua on a partitioned table which contains 1000 partitions and 100 records each partition. Use 10 client threads to simply prove the performance effect. Before optimization: Throughput: events/s (eps): 120421.8384 time elapsed: 180.0025s total number of events: 21676232 After optimization: Throughput: events/s (eps): 124797.5937 time elapsed: 180.0025s total number of events: 22463880 The performance improvement rate is about 3.5%. Author: hopebo --- storage/innobase/handler/ha_innopart.cc | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/storage/innobase/handler/ha_innopart.cc b/storage/innobase/handler/ha_innopart.cc index 651cd4b4dfd..0306b54d84e 100644 --- a/storage/innobase/handler/ha_innopart.cc +++ b/storage/innobase/handler/ha_innopart.cc @@ -3985,7 +3985,8 @@ THR_LOCK_DATA **ha_innopart::store_lock(THD *thd, THR_LOCK_DATA **to, ha_innobase::store_lock(thd, to, lock_type); if (sql_command == SQLCOM_FLUSH && lock_type == TL_READ_NO_INSERT) { - for (uint i = 1; i < m_tot_parts; i++) { + for (uint i = m_part_info->get_first_used_partition(); i < m_tot_parts; + i = m_part_info->get_next_used_partition(i)) { dict_table_t *table = m_part_share->get_table_part(i); dberr_t err = row_quiesce_set_state(table, QUIESCE_START, trx); @@ -4033,7 +4034,8 @@ int ha_innopart::external_lock(THD *thd, int lock_type) { m_prebuilt->table = m_part_share->get_table_part(0); error = ha_innobase::external_lock(thd, lock_type); - for (uint i = 0; i < m_tot_parts; i++) { + for (uint i = m_part_info->get_first_used_partition(); i < m_tot_parts; + i = m_part_info->get_next_used_partition(i)) { dict_table_t *table = m_part_share->get_table_part(i); switch (table->quiesce) { @@ -4169,7 +4171,11 @@ void ha_innopart::clear_blob_heaps() { return; } - for (uint i = 0; i < m_tot_parts; i++) { + /* For unordered scan and table scan, use blob_heap from first partition as + we need exactly one blob. Regardless of whether the first partition is used, + its blob heap should be cleared. */ + for (uint i = 0; i < m_tot_parts; + i = m_part_info->get_next_used_partition(i)) { if (m_blob_heap_parts[i] != nullptr) { DBUG_PRINT("ha_innopart", ("freeing blob_heap: %p", m_blob_heap_parts[i])); @@ -4178,6 +4184,11 @@ void ha_innopart::clear_blob_heaps() { } } +#ifdef UNIV_DEBUG + for (uint i = 0; i < m_tot_parts; i++) + ut_ad(m_blob_heap_parts[i] == nullptr); +#endif + /* Reset blob_heap in m_prebuilt after freeing all heaps. It is set in ha_innopart::set_partition to the blob heap of current partition. */ m_prebuilt->blob_heap = nullptr; -- 2.19.1.3.ge56e4f7