Columnar: Fix VACUUM for empty tables

pull/4375/head
Hadi Moshayedi 2020-12-01 11:57:40 -08:00
parent c4f36c195f
commit 24bfd368a9
5 changed files with 164 additions and 3 deletions

View File

@ -607,13 +607,23 @@ StripesForRelfilenode(RelFileNode relfilenode)
/*
* GetHighestUsedAddress returns the highest used address for the given
* relfilenode across all active and inactive transactions.
*
* This is used by truncate stage of VACUUM, and VACUUM can be called
* for empty tables. So this doesn't throw errors for empty tables and
* returns 0.
*/
uint64
GetHighestUsedAddress(RelFileNode relfilenode)
{
uint64 highestUsedAddress = 0;
uint64 highestUsedId = 0;
ColumnarMetapage *metapage = ReadMetapage(relfilenode, false);
ColumnarMetapage *metapage = ReadMetapage(relfilenode, true);
/* empty data file? */
if (metapage == NULL)
{
return 0;
}
GetHighestUsedAddressAndId(metapage->storageId, &highestUsedAddress, &highestUsedId);

View File

@ -743,7 +743,8 @@ LogRelationStats(Relation rel, int elevel)
appendStringInfo(infoBuf,
"total row count: %ld, stripe count: %d, "
"average rows per stripe: %ld\n",
tupleCount, stripeCount, tupleCount / stripeCount);
tupleCount, stripeCount,
stripeCount ? tupleCount / stripeCount : 0);
appendStringInfo(infoBuf,
"block count: %ld"
", containing data for dropped columns: %ld",
@ -817,7 +818,11 @@ TruncateCStore(Relation rel, int elevel)
SmgrAddr highestPhysicalAddress =
logical_to_smgr(GetHighestUsedAddress(rel->rd_node));
BlockNumber new_rel_pages = highestPhysicalAddress.blockno + 1;
/*
* Unlock and return if truncation won't reduce data file's size.
*/
BlockNumber new_rel_pages = Min(old_rel_pages,
highestPhysicalAddress.blockno + 1);
if (new_rel_pages == old_rel_pages)
{
UnlockRelation(rel, AccessExclusiveLock);

View File

@ -8,6 +8,7 @@ test: am_query
test: am_analyze
test: am_data_types
test: am_drop
test: am_empty
test: am_insert
test: am_copyto
test: am_alter

View File

@ -0,0 +1,97 @@
--
-- Test different operations on empty columnar tables.
--
SET citus.compression to 'none';
create table t_uncompressed(a int) using columnar;
create table t_compressed(a int) using columnar;
-- set options
SELECT alter_columnar_table_set('t_compressed', compression => 'pglz');
alter_columnar_table_set
---------------------------------------------------------------------
(1 row)
SELECT alter_columnar_table_set('t_compressed', stripe_row_count => 100);
alter_columnar_table_set
---------------------------------------------------------------------
(1 row)
SELECT alter_columnar_table_set('t_compressed', block_row_count => 100);
alter_columnar_table_set
---------------------------------------------------------------------
(1 row)
SELECT * FROM cstore.options WHERE regclass = 't_compressed'::regclass;
regclass | block_row_count | stripe_row_count | compression
---------------------------------------------------------------------
t_compressed | 100 | 100 | pglz
(1 row)
-- select
select * from t_uncompressed;
a
---------------------------------------------------------------------
(0 rows)
select count(*) from t_uncompressed;
count
---------------------------------------------------------------------
0
(1 row)
select * from t_compressed;
a
---------------------------------------------------------------------
(0 rows)
select count(*) from t_compressed;
count
---------------------------------------------------------------------
0
(1 row)
-- explain
explain (costs off, summary off, timing off) select * from t_uncompressed;
QUERY PLAN
---------------------------------------------------------------------
Custom Scan (CStoreScan) on t_uncompressed
(1 row)
explain (costs off, summary off, timing off) select * from t_compressed;
QUERY PLAN
---------------------------------------------------------------------
Custom Scan (CStoreScan) on t_compressed
(1 row)
-- vacuum
vacuum verbose t_compressed;
INFO: statistics for "t_compressed":
storage id: -1
total file size: 0, total data size: 0
total row count: 0, stripe count: 0, average rows per stripe: 0
block count: 0, containing data for dropped columns: 0, none compressed: 0, pglz compressed: 0
vacuum verbose t_uncompressed;
INFO: statistics for "t_uncompressed":
storage id: -1
total file size: 0, total data size: 0
total row count: 0, stripe count: 0, average rows per stripe: 0
block count: 0, containing data for dropped columns: 0, none compressed: 0, pglz compressed: 0
-- vacuum full
vacuum full t_compressed;
vacuum full t_uncompressed;
-- analyze
analyze t_uncompressed;
analyze t_compressed;
-- truncate
truncate t_uncompressed;
truncate t_compressed;
-- alter type
alter table t_uncompressed alter column a type text;
alter table t_compressed alter column a type text;
-- drop
drop table t_compressed;
drop table t_uncompressed;

View File

@ -0,0 +1,48 @@
--
-- Test different operations on empty columnar tables.
--
SET citus.compression to 'none';
create table t_uncompressed(a int) using columnar;
create table t_compressed(a int) using columnar;
-- set options
SELECT alter_columnar_table_set('t_compressed', compression => 'pglz');
SELECT alter_columnar_table_set('t_compressed', stripe_row_count => 100);
SELECT alter_columnar_table_set('t_compressed', block_row_count => 100);
SELECT * FROM cstore.options WHERE regclass = 't_compressed'::regclass;
-- select
select * from t_uncompressed;
select count(*) from t_uncompressed;
select * from t_compressed;
select count(*) from t_compressed;
-- explain
explain (costs off, summary off, timing off) select * from t_uncompressed;
explain (costs off, summary off, timing off) select * from t_compressed;
-- vacuum
vacuum verbose t_compressed;
vacuum verbose t_uncompressed;
-- vacuum full
vacuum full t_compressed;
vacuum full t_uncompressed;
-- analyze
analyze t_uncompressed;
analyze t_compressed;
-- truncate
truncate t_uncompressed;
truncate t_compressed;
-- alter type
alter table t_uncompressed alter column a type text;
alter table t_compressed alter column a type text;
-- drop
drop table t_compressed;
drop table t_uncompressed;