Commit f2d7609a authored by Michael Widenius's avatar Michael Widenius

Use less memory when growing HEAP tables. See MDEV-436

mysql-test/suite/heap/heap.result:
  Added test case for MDEV-436
mysql-test/suite/heap/heap.test:
  Added test case for MDEV-436
storage/heap/hp_block.c:
  Don't allocate a set of HP_PTRS when not needed. This saves us about 1024 bytes for most allocations.
storage/heap/hp_create.c:
  Made the initial allocation of block sizes depending on min_records and max_records.
parent a7123f50
...@@ -738,3 +738,27 @@ SELECT c2 FROM t1; ...@@ -738,3 +738,27 @@ SELECT c2 FROM t1;
c2 c2
0 0
DROP TABLE t1; DROP TABLE t1;
CREATE TABLE t1 (a int, index(a)) engine=heap min_rows=10 max_rows=100;
insert into t1 values(1);
select data_length,index_length from information_schema.tables where table_schema="test" and table_name="t1";
data_length index_length
1600 2400
drop table t1;
CREATE TABLE t1 (a int, index(a)) engine=heap min_rows=10 max_rows=10000;
insert into t1 values(1);
select data_length,index_length from information_schema.tables where table_schema="test" and table_name="t1";
data_length index_length
16000 24000
drop table t1;
CREATE TABLE t1 (a int, index(a)) engine=heap min_rows=3000 max_rows=3000;
insert into t1 values(1);
select data_length,index_length from information_schema.tables where table_schema="test" and table_name="t1";
data_length index_length
48000 72000
drop table t1;
CREATE TABLE t1 (a int, index(a)) engine=heap max_rows=4000;
insert into t1 values(1);
select data_length,index_length from information_schema.tables where table_schema="test" and table_name="t1";
data_length index_length
16000 24000
drop table t1;
...@@ -485,3 +485,26 @@ INSERT INTO t1 VALUES('', 0); ...@@ -485,3 +485,26 @@ INSERT INTO t1 VALUES('', 0);
ALTER TABLE t1 MODIFY c1 VARCHAR(101); ALTER TABLE t1 MODIFY c1 VARCHAR(101);
SELECT c2 FROM t1; SELECT c2 FROM t1;
DROP TABLE t1; DROP TABLE t1;
#
# Show that MIN_ROWS and MAX_ROWS have an effect on how data_length
# and index_length are allocated.
# This is different for 32 and 64 bit machines as pointer lengths are different
#
CREATE TABLE t1 (a int, index(a)) engine=heap min_rows=10 max_rows=100;
insert into t1 values(1);
select data_length,index_length from information_schema.tables where table_schema="test" and table_name="t1";
drop table t1;
CREATE TABLE t1 (a int, index(a)) engine=heap min_rows=10 max_rows=10000;
insert into t1 values(1);
select data_length,index_length from information_schema.tables where table_schema="test" and table_name="t1";
drop table t1;
CREATE TABLE t1 (a int, index(a)) engine=heap min_rows=3000 max_rows=3000;
insert into t1 values(1);
select data_length,index_length from information_schema.tables where table_schema="test" and table_name="t1";
drop table t1;
CREATE TABLE t1 (a int, index(a)) engine=heap max_rows=4000;
insert into t1 values(1);
select data_length,index_length from information_schema.tables where table_schema="test" and table_name="t1";
drop table t1;
...@@ -64,18 +64,19 @@ int hp_get_new_block(HP_BLOCK *block, size_t *alloc_length) ...@@ -64,18 +64,19 @@ int hp_get_new_block(HP_BLOCK *block, size_t *alloc_length)
break; break;
/* /*
Allocate space for leaf block plus space for upper level blocks up to Allocate space for leaf block (data) plus space for upper level blocks
first level that has a free slot to put the pointer. up to first level that has a free slot to put the pointer.
In some cases we actually allocate more then we need: If this is a new level, we have to allocate pointers to all future
Consider e.g. a situation where we have one level 1 block and one level 0 lower levels.
block, the level 0 block is full and this function is called. We only
need a leaf block in this case. Nevertheless, we will get here with i=1 For example, for level 0, we allocate data for X rows.
and will also allocate sizeof(HP_PTRS) for non-leaf block and will never When level 0 is full, we allocate data for HPTRS_IN_NODE + X rows.
use this space. Next time we allocate data for X rows.
This doesn't add much overhead - with current values of sizeof(HP_PTRS) When level 1 is full, we allocate data for HPTRS_IN_NODE at level 2 and 1
and my_default_record_cache_size we get about 1/128 unused memory. + X rows at level 0.
*/ */
*alloc_length=sizeof(HP_PTRS)*i+block->records_in_block* block->recbuffer; *alloc_length= (sizeof(HP_PTRS)* ((i == block->levels) ? i : i - 1) +
block->records_in_block* block->recbuffer);
if (!(root=(HP_PTRS*) my_malloc(*alloc_length,MYF(MY_WME)))) if (!(root=(HP_PTRS*) my_malloc(*alloc_length,MYF(MY_WME))))
return 1; return 1;
......
...@@ -245,21 +245,32 @@ static void init_block(HP_BLOCK *block, uint reclength, ulong min_records, ...@@ -245,21 +245,32 @@ static void init_block(HP_BLOCK *block, uint reclength, ulong min_records,
{ {
uint i,recbuffer,records_in_block; uint i,recbuffer,records_in_block;
max_records= max(min_records,max_records); /*
If not min_records and max_records are given, optimize for 1000 rows
*/
if (!min_records)
min_records= min(1000, max_records);
if (!max_records) if (!max_records)
max_records= 1000; /* As good as quess as anything */ max_records= max(min_records, 1000);
recbuffer= (uint) (reclength + sizeof(uchar**) - 1) & ~(sizeof(uchar**) - 1);
records_in_block= max_records / 10;
/* /*
We don't want too few records_in_block as otherwise the overhead of We don't want too few records_in_block as otherwise the overhead of
of the HP_PTRS block will be too notable of the HP_PTRS block will be too notable
*/ */
records_in_block= min(1000, max_records); records_in_block= max(1000, min_records);
records_in_block= min(records_in_block, max_records);
/* If big max_records is given, allocate bigger blocks */
records_in_block= max(records_in_block, max_records / 10);
/* We don't want too few blocks per row either */
if (records_in_block < 10) if (records_in_block < 10)
records_in_block= 10; records_in_block= 10;
/* The + 1 is there to ensure that we get at least 1 row per level */ recbuffer= (uint) (reclength + sizeof(uchar**) - 1) & ~(sizeof(uchar**) - 1);
/*
Don't allocate more than my_default_record_cache_size per level.
The + 1 is there to ensure that we get at least 1 row per level (for
the exceptional case of very long rows)
*/
if (records_in_block*recbuffer > if (records_in_block*recbuffer >
(my_default_record_cache_size-sizeof(HP_PTRS)*HP_MAX_LEVELS)) (my_default_record_cache_size-sizeof(HP_PTRS)*HP_MAX_LEVELS))
records_in_block= (my_default_record_cache_size - sizeof(HP_PTRS) * records_in_block= (my_default_record_cache_size - sizeof(HP_PTRS) *
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment