From 07d3b4fd040efd9998d379096ab5eb63f862315b Mon Sep 17 00:00:00 2001 From: Nils Dijk Date: Wed, 27 Jan 2021 17:32:17 +0100 Subject: [PATCH] fix NaN cost estimate on empty columnar tables (#4593) Fixing a division by zero in the cost calculations for scanning a columnar table. Due to how the columns in a columnar table are counted an empty table would result in a division by zero. Instead this patch keeps the column selection ratio on zero when this happens, resulting in an accurate cost of zero pages to scan a columnar table. fixes #4589 --- src/backend/columnar/cstore_customscan.c | 13 ++++++++++++- src/test/regress/expected/am_empty.out | 13 +++++++++++++ src/test/regress/sql/am_empty.sql | 4 ++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/backend/columnar/cstore_customscan.c b/src/backend/columnar/cstore_customscan.c index a42d9842e..e1dfee2ac 100644 --- a/src/backend/columnar/cstore_customscan.c +++ b/src/backend/columnar/cstore_customscan.c @@ -242,7 +242,18 @@ ColumnarScanCost(RangeTblEntry *rte) { Bitmapset *attr_needed = rte->selectedCols; double numberOfColumnsRead = bms_num_members(attr_needed); - double selectionRatio = numberOfColumnsRead / (double) maxColumnCount; + double selectionRatio = 0; + + /* + * When no stripes are in the table we don't have a count in maxColumnCount. To + * prevent a division by zero turning into a NaN we keep the ratio on zero. + * This will result in a cost of 0 for scanning the table which is a reasonable + * cost on an empty table. + */ + if (maxColumnCount != 0) + { + selectionRatio = numberOfColumnsRead / (double) maxColumnCount; + } Cost scanCost = (double) totalStripeSize / BLCKSZ * selectionRatio; return scanCost; } diff --git a/src/test/regress/expected/am_empty.out b/src/test/regress/expected/am_empty.out index 2473cb8ce..d17b11184 100644 --- a/src/test/regress/expected/am_empty.out +++ b/src/test/regress/expected/am_empty.out @@ -94,6 +94,19 @@ truncate t_compressed; -- alter type alter table t_uncompressed alter column a type text; alter table t_compressed alter column a type text; +-- verify cost of scanning an empty table is zero, not NaN +explain table t_uncompressed; + QUERY PLAN +--------------------------------------------------------------------- + Custom Scan (ColumnarScan) on t_uncompressed (cost=0.00..0.00 rows=1 width=32) +(1 row) + +explain table t_compressed; + QUERY PLAN +--------------------------------------------------------------------- + Custom Scan (ColumnarScan) on t_compressed (cost=0.00..0.00 rows=1 width=32) +(1 row) + -- drop drop table t_compressed; drop table t_uncompressed; diff --git a/src/test/regress/sql/am_empty.sql b/src/test/regress/sql/am_empty.sql index 9e698676f..01e73c6f6 100644 --- a/src/test/regress/sql/am_empty.sql +++ b/src/test/regress/sql/am_empty.sql @@ -43,6 +43,10 @@ truncate t_compressed; alter table t_uncompressed alter column a type text; alter table t_compressed alter column a type text; +-- verify cost of scanning an empty table is zero, not NaN +explain table t_uncompressed; +explain table t_compressed; + -- drop drop table t_compressed; drop table t_uncompressed;