Skip to content

Commit 3e2de58

Browse files
author
Aditya A
committed
Bug #17780517 5.6 PARTITIONS USE MUCH MORE MEMORY THAN 5.1
PROBLEM ------- More memory usage was seen due to increase in size of ha_innobase object . The two character arrays srch_key_val* in ha_innobase class each contribute approximately 6Kbytes ,so when large databases with many partitions are used ,memory usage increases. FIX --- MySQL stores the INTs datatypes in little endian format where as innodb stores them in big endian format.The srch_key_val* arrays are only needed when we are converting INTs datatypes in the search key from little endian format to big endian format. So we allocate memory equivalent to number of INTs in each index of the table ,which will reduce memory footprint. Also we have moved the allocation of the memory to ha_innobase::open() so that the memory is only allocated during opening of table handler. [Approved by Mattiasj and Jimmy #rb5565]
1 parent ffdecce commit 3e2de58

File tree

5 files changed

+72
-21
lines changed

5 files changed

+72
-21
lines changed

storage/innobase/handler/ha_innodb.cc

+6-3
Original file line numberDiff line numberDiff line change
@@ -7470,7 +7470,8 @@ ha_innobase::index_read(
74707470

74717471
row_sel_convert_mysql_key_to_innobase(
74727472
prebuilt->search_tuple,
7473-
srch_key_val1, sizeof(srch_key_val1),
7473+
prebuilt->srch_key_val1,
7474+
prebuilt->srch_key_val_len,
74747475
index,
74757476
(byte*) key_ptr,
74767477
(ulint) key_len,
@@ -10410,7 +10411,8 @@ ha_innobase::records_in_range(
1041010411

1041110412
row_sel_convert_mysql_key_to_innobase(
1041210413
range_start,
10413-
srch_key_val1, sizeof(srch_key_val1),
10414+
prebuilt->srch_key_val1,
10415+
prebuilt->srch_key_val_len,
1041410416
index,
1041510417
(byte*) (min_key ? min_key->key :
1041610418
(const uchar*) 0),
@@ -10422,7 +10424,8 @@ ha_innobase::records_in_range(
1042210424

1042310425
row_sel_convert_mysql_key_to_innobase(
1042410426
range_end,
10425-
srch_key_val2, sizeof(srch_key_val2),
10427+
prebuilt->srch_key_val2,
10428+
prebuilt->srch_key_val_len,
1042610429
index,
1042710430
(byte*) (max_key ? max_key->key :
1042810431
(const uchar*) 0),

storage/innobase/handler/ha_innodb.h

-7
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,6 @@ class ha_innobase: public handler
7171

7272
uchar* upd_buf; /*!< buffer used in updates */
7373
ulint upd_buf_size; /*!< the size of upd_buf in bytes */
74-
uchar srch_key_val1[MAX_KEY_LENGTH + MAX_REF_PARTS*2];
75-
uchar srch_key_val2[MAX_KEY_LENGTH + MAX_REF_PARTS*2];
76-
/*!< buffers used in converting
77-
search key values from MySQL format
78-
to InnoDB format. For each column
79-
2 bytes are used to store length,
80-
hence MAX_REF_PARTS*2. */
8174
Table_flags int_table_flags;
8275
uint primary_key;
8376
ulong start_of_scan; /*!< this is set to 1 when we are

storage/innobase/include/row0mysql.h

+8
Original file line numberDiff line numberDiff line change
@@ -871,6 +871,14 @@ struct row_prebuilt_t {
871871
unsigned innodb_api:1; /*!< whether this is a InnoDB API
872872
query */
873873
const rec_t* innodb_api_rec; /*!< InnoDB API search result */
874+
byte* srch_key_val1; /*!< buffer used in converting
875+
search key values from MySQL format
876+
to InnoDB format.*/
877+
byte* srch_key_val2; /*!< buffer used in converting
878+
search key values from MySQL format
879+
to InnoDB format.*/
880+
uint srch_key_val_len; /*!< Size of search key */
881+
874882
};
875883

876884
/** Callback for row_mysql_sys_index_iterate() */

storage/innobase/row/row0mysql.cc

+52-1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ Created 9/17/2000 Heikki Tuuri
3333
#include <debug_sync.h>
3434
#include <my_dbug.h>
3535

36+
#include <sql_const.h>
3637
#include "row0ins.h"
3738
#include "row0merge.h"
3839
#include "row0sel.h"
@@ -711,8 +712,10 @@ row_create_prebuilt(
711712
row_prebuilt_t* prebuilt;
712713
mem_heap_t* heap;
713714
dict_index_t* clust_index;
715+
dict_index_t* temp_index;
714716
dtuple_t* ref;
715717
ulint ref_len;
718+
uint srch_key_len = 0;
716719
ulint search_tuple_n_fields;
717720

718721
search_tuple_n_fields = 2 * dict_table_get_n_cols(table);
@@ -724,6 +727,14 @@ row_create_prebuilt(
724727

725728
ref_len = dict_index_get_n_unique(clust_index);
726729

730+
731+
/* Maximum size of the buffer needed for conversion of INTs from
732+
little endian format to big endian format in an index. An index
733+
can have maximum 16 columns (MAX_REF_PARTS) in it. Therfore
734+
Max size for PK: 16 * 8 bytes (BIGINT's size) = 128 bytes
735+
Max size Secondary index: 16 * 8 bytes + PK = 256 bytes. */
736+
#define MAX_SRCH_KEY_VAL_BUFFER 2* (8 * MAX_REF_PARTS)
737+
727738
#define PREBUILT_HEAP_INITIAL_SIZE \
728739
( \
729740
sizeof(*prebuilt) \
@@ -752,10 +763,38 @@ row_create_prebuilt(
752763
+ sizeof(que_thr_t) \
753764
)
754765

766+
/* Calculate size of key buffer used to store search key in
767+
InnoDB format. MySQL stores INTs in little endian format and
768+
InnoDB stores INTs in big endian format with the sign bit
769+
flipped. All other field types are stored/compared the same
770+
in MySQL and InnoDB, so we must create a buffer containing
771+
the INT key parts in InnoDB format.We need two such buffers
772+
since both start and end keys are used in records_in_range(). */
773+
774+
for (temp_index = dict_table_get_first_index(table); temp_index;
775+
temp_index = dict_table_get_next_index(temp_index)) {
776+
DBUG_EXECUTE_IF("innodb_srch_key_buffer_max_value",
777+
ut_a(temp_index->n_user_defined_cols
778+
== MAX_REF_PARTS););
779+
uint temp_len = 0;
780+
for (int i = 0; i < temp_index->n_uniq; i++) {
781+
if (temp_index->fields[i].col->mtype == DATA_INT) {
782+
temp_len +=
783+
temp_index->fields[i].fixed_len;
784+
}
785+
}
786+
srch_key_len = max(srch_key_len,temp_len);
787+
}
788+
789+
ut_a(srch_key_len <= MAX_SRCH_KEY_VAL_BUFFER);
790+
791+
DBUG_EXECUTE_IF("innodb_srch_key_buffer_max_value",
792+
ut_a(srch_key_len == MAX_SRCH_KEY_VAL_BUFFER););
793+
755794
/* We allocate enough space for the objects that are likely to
756795
be created later in order to minimize the number of malloc()
757796
calls */
758-
heap = mem_heap_create(PREBUILT_HEAP_INITIAL_SIZE);
797+
heap = mem_heap_create(PREBUILT_HEAP_INITIAL_SIZE + 2 * srch_key_len);
759798

760799
prebuilt = static_cast<row_prebuilt_t*>(
761800
mem_heap_zalloc(heap, sizeof(*prebuilt)));
@@ -768,6 +807,18 @@ row_create_prebuilt(
768807
prebuilt->sql_stat_start = TRUE;
769808
prebuilt->heap = heap;
770809

810+
prebuilt->srch_key_val_len = srch_key_len;
811+
if (prebuilt->srch_key_val_len) {
812+
prebuilt->srch_key_val1 = static_cast<byte*>(
813+
mem_heap_alloc(prebuilt->heap,
814+
2 * prebuilt->srch_key_val_len));
815+
prebuilt->srch_key_val2 = prebuilt->srch_key_val1 +
816+
prebuilt->srch_key_val_len;
817+
} else {
818+
prebuilt->srch_key_val1 = NULL;
819+
prebuilt->srch_key_val2 = NULL;
820+
}
821+
771822
btr_pcur_reset(&prebuilt->pcur);
772823
btr_pcur_reset(&prebuilt->clust_pcur);
773824

storage/innobase/row/row0sel.cc

+6-10
Original file line numberDiff line numberDiff line change
@@ -2455,13 +2455,12 @@ row_sel_convert_mysql_key_to_innobase(
24552455
/* Storing may use at most data_len bytes of buf */
24562456

24572457
if (UNIV_LIKELY(!is_null)) {
2458-
ut_a(buf + data_len <= original_buf + buf_len);
2459-
row_mysql_store_col_in_innobase_format(
2460-
dfield, buf,
2461-
FALSE, /* MySQL key value format col */
2462-
key_ptr + data_offset, data_len,
2463-
dict_table_is_comp(index->table));
2464-
buf += data_len;
2458+
buf = row_mysql_store_col_in_innobase_format(
2459+
dfield, buf,
2460+
FALSE, /* MySQL key value format col */
2461+
key_ptr + data_offset, data_len,
2462+
dict_table_is_comp(index->table));
2463+
ut_a(buf <= original_buf + buf_len);
24652464
}
24662465

24672466
key_ptr += data_field_len;
@@ -2505,9 +2504,6 @@ row_sel_convert_mysql_key_to_innobase(
25052504
dfield++;
25062505
}
25072506

2508-
DBUG_EXECUTE_IF("innodb_srch_key_buffer_full",
2509-
ut_a(buf == (original_buf + buf_len)););
2510-
25112507
ut_a(buf <= original_buf + buf_len);
25122508

25132509
/* We set the length of tuple to n_fields: we assume that the memory

0 commit comments

Comments
 (0)