From 0b5551faaf553efae65a8b611ed192becbe3496f Mon Sep 17 00:00:00 2001 From: jeff-davis Date: Thu, 21 Jan 2021 15:04:42 -0800 Subject: [PATCH] Columnar: add explain info for chunk filtering (#4554) Co-authored-by: Jeff Davis --- src/backend/columnar/cstore_customscan.c | 19 +++++++++++++++++- src/backend/columnar/cstore_reader.c | 18 +++++++++++------ src/backend/columnar/cstore_tableam.c | 20 +++++++++++++++++++ src/include/columnar/cstore.h | 1 + src/include/columnar/cstore_tableam.h | 2 +- .../regress/input/am_chunk_filtering.source | 6 ++++++ .../regress/output/am_chunk_filtering.source | 13 ++++++++++++ 7 files changed, 71 insertions(+), 8 deletions(-) diff --git a/src/backend/columnar/cstore_customscan.c b/src/backend/columnar/cstore_customscan.c index e8117a070..dcde6d186 100644 --- a/src/backend/columnar/cstore_customscan.c +++ b/src/backend/columnar/cstore_customscan.c @@ -68,6 +68,8 @@ static void CStoreScan_BeginCustomScan(CustomScanState *node, EState *estate, in static TupleTableSlot * CStoreScan_ExecCustomScan(CustomScanState *node); static void CStoreScan_EndCustomScan(CustomScanState *node); static void CStoreScan_ReScanCustomScan(CustomScanState *node); +static void CStoreScan_ExplainCustomScan(CustomScanState *node, List *ancestors, + ExplainState *es); /* saved hook value in case of unload */ static set_rel_pathlist_hook_type PreviousSetRelPathlistHook = NULL; @@ -93,7 +95,7 @@ const struct CustomExecMethods CStoreExecuteMethods = { .EndCustomScan = CStoreScan_EndCustomScan, .ReScanCustomScan = CStoreScan_ReScanCustomScan, - .ExplainCustomScan = NULL, + .ExplainCustomScan = CStoreScan_ExplainCustomScan, }; @@ -439,4 +441,19 @@ CStoreScan_ReScanCustomScan(CustomScanState *node) } +static void +CStoreScan_ExplainCustomScan(CustomScanState *node, List *ancestors, + ExplainState *es) +{ + TableScanDesc scanDesc = node->ss.ss_currentScanDesc; + + if (scanDesc != NULL) + { + int64 chunksFiltered = ColumnarGetChunksFiltered(scanDesc); + ExplainPropertyInteger("Columnar Chunks Removed by Filter", NULL, + chunksFiltered, es); + } +} + + #endif /* HAS_TABLEAM */ diff --git a/src/backend/columnar/cstore_reader.c b/src/backend/columnar/cstore_reader.c index ee2e49f8b..ebbf5bb53 100644 --- a/src/backend/columnar/cstore_reader.c +++ b/src/backend/columnar/cstore_reader.c @@ -44,7 +44,8 @@ static StripeBuffers * LoadFilteredStripeBuffers(Relation relation, StripeMetadata *stripeMetadata, TupleDesc tupleDescriptor, List *projectedColumnList, - List *whereClauseList); + List *whereClauseList, + int64 *chunksFiltered); static void ReadStripeNextRow(StripeBuffers *stripeBuffers, List *projectedColumnList, uint64 chunkIndex, uint64 chunkRowIndex, ChunkData *chunkData, Datum *columnValues, @@ -54,7 +55,8 @@ static ColumnBuffers * LoadColumnBuffers(Relation relation, uint32 chunkCount, uint64 stripeOffset, Form_pg_attribute attributeForm); static bool * SelectedChunkMask(StripeSkipList *stripeSkipList, - List *projectedColumnList, List *whereClauseList); + List *projectedColumnList, List *whereClauseList, + int64 *chunksFiltered); static List * BuildRestrictInfoList(List *whereClauseList); static Node * BuildBaseConstraint(Var *variable); static OpExpr * MakeOpExpression(Var *variable, int16 strategyNumber); @@ -104,6 +106,7 @@ CStoreBeginRead(Relation relation, TupleDesc tupleDescriptor, readState->stripeBuffers = NULL; readState->readStripeCount = 0; readState->stripeReadRowCount = 0; + readState->chunksFiltered = 0; readState->tupleDescriptor = tupleDescriptor; readState->stripeReadContext = stripeReadContext; readState->chunkData = NULL; @@ -153,7 +156,9 @@ CStoreReadNextRow(TableReadState *readState, Datum *columnValues, bool *columnNu readState-> projectedColumnList, readState-> - whereClauseList); + whereClauseList, + &readState-> + chunksFiltered); readState->readStripeCount++; readState->currentStripeMetadata = stripeMetadata; @@ -332,7 +337,7 @@ CStoreTableRowCount(Relation relation) static StripeBuffers * LoadFilteredStripeBuffers(Relation relation, StripeMetadata *stripeMetadata, TupleDesc tupleDescriptor, List *projectedColumnList, - List *whereClauseList) + List *whereClauseList, int64 *chunksFiltered) { uint32 columnIndex = 0; uint32 columnCount = tupleDescriptor->natts; @@ -345,7 +350,7 @@ LoadFilteredStripeBuffers(Relation relation, StripeMetadata *stripeMetadata, stripeMetadata->chunkCount); bool *selectedChunkMask = SelectedChunkMask(stripeSkipList, projectedColumnList, - whereClauseList); + whereClauseList, chunksFiltered); StripeSkipList *selectedChunkSkipList = SelectedChunkSkipList(stripeSkipList, projectedColumnMask, @@ -474,7 +479,7 @@ LoadColumnBuffers(Relation relation, ColumnChunkSkipNode *chunkSkipNodeArray, */ static bool * SelectedChunkMask(StripeSkipList *stripeSkipList, List *projectedColumnList, - List *whereClauseList) + List *whereClauseList, int64 *chunksFiltered) { ListCell *columnCell = NULL; uint32 chunkIndex = 0; @@ -527,6 +532,7 @@ SelectedChunkMask(StripeSkipList *stripeSkipList, List *projectedColumnList, if (predicateRefuted) { selectedChunkMask[chunkIndex] = false; + *chunksFiltered += 1; } } } diff --git a/src/backend/columnar/cstore_tableam.c b/src/backend/columnar/cstore_tableam.c index 293935e56..34055db58 100644 --- a/src/backend/columnar/cstore_tableam.c +++ b/src/backend/columnar/cstore_tableam.c @@ -1156,6 +1156,26 @@ cstore_tableam_finish() } +/* + * Get the number of chunks filtered out during the given scan. + */ +int64 +ColumnarGetChunksFiltered(TableScanDesc scanDesc) +{ + CStoreScanDesc cstoreScanDesc = (CStoreScanDesc) scanDesc; + TableReadState *readState = cstoreScanDesc->cs_readState; + + if (readState != NULL) + { + return readState->chunksFiltered; + } + else + { + return 0; + } +} + + /* * Implementation of TupleTableSlotOps.copy_heap_tuple for TTSOpsColumnar. */ diff --git a/src/include/columnar/cstore.h b/src/include/columnar/cstore.h index 6548887a0..7f6a81d6a 100644 --- a/src/include/columnar/cstore.h +++ b/src/include/columnar/cstore.h @@ -236,6 +236,7 @@ typedef struct TableReadState StripeBuffers *stripeBuffers; uint32 readStripeCount; uint64 stripeReadRowCount; + int64 chunksFiltered; ChunkData *chunkData; int32 deserializedChunkIndex; } TableReadState; diff --git a/src/include/columnar/cstore_tableam.h b/src/include/columnar/cstore_tableam.h index 71f223678..862af4357 100644 --- a/src/include/columnar/cstore_tableam.h +++ b/src/include/columnar/cstore_tableam.h @@ -18,7 +18,7 @@ extern TableScanDesc cstore_beginscan_extended(Relation relation, Snapshot snaps ParallelTableScanDesc parallel_scan, uint32 flags, Bitmapset *attr_needed, List *scanQual); - +extern int64 ColumnarGetChunksFiltered(TableScanDesc scanDesc); extern bool IsCStoreTableAmTable(Oid relationId); extern TableDDLCommand * ColumnarGetTableOptionsDDL(Oid relationId); extern char * GetShardedTableDDLCommandColumnar(uint64 shardId, void *context); diff --git a/src/test/regress/input/am_chunk_filtering.source b/src/test/regress/input/am_chunk_filtering.source index 4020f9499..41c098528 100644 --- a/src/test/regress/input/am_chunk_filtering.source +++ b/src/test/regress/input/am_chunk_filtering.source @@ -71,3 +71,9 @@ B \. SELECT * FROM collation_chunk_filtering_test WHERE A > 'B'; + +CREATE TABLE simple_chunk_filtering(i int) USING COLUMNAR; +INSERT INTO simple_chunk_filtering SELECT generate_series(0,234567); +EXPLAIN (analyze on, costs off, timing off, summary off) + SELECT * FROM simple_chunk_filtering WHERE i > 123456; +DROP TABLE simple_chunk_filtering; diff --git a/src/test/regress/output/am_chunk_filtering.source b/src/test/regress/output/am_chunk_filtering.source index ff52a618c..9a42d7230 100644 --- a/src/test/regress/output/am_chunk_filtering.source +++ b/src/test/regress/output/am_chunk_filtering.source @@ -118,3 +118,16 @@ SELECT * FROM collation_chunk_filtering_test WHERE A > 'B'; Å (1 row) +CREATE TABLE simple_chunk_filtering(i int) USING COLUMNAR; +INSERT INTO simple_chunk_filtering SELECT generate_series(0,234567); +EXPLAIN (analyze on, costs off, timing off, summary off) + SELECT * FROM simple_chunk_filtering WHERE i > 123456; + QUERY PLAN +--------------------------------------------------------------------- + Custom Scan (ColumnarScan) on simple_chunk_filtering (actual rows=111111 loops=1) + Filter: (i > 123456) + Rows Removed by Filter: 3457 + Columnar Chunks Removed by Filter: 12 +(4 rows) + +DROP TABLE simple_chunk_filtering;