mirror of https://github.com/citusdata/citus.git
Merge pull request #4407 from citusdata/cstore_analyze
Columnar: Fix ANALYZE for large number of rows.pull/4384/head
commit
e24e7985f7
|
@ -81,6 +81,12 @@ typedef struct CStoreScanDescData
|
||||||
MemoryContext scanContext;
|
MemoryContext scanContext;
|
||||||
Bitmapset *attr_needed;
|
Bitmapset *attr_needed;
|
||||||
List *scanQual;
|
List *scanQual;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ANALYZE requires an item pointer for sorting. We keep track of row
|
||||||
|
* number so we can construct an item pointer based on that.
|
||||||
|
*/
|
||||||
|
int rowNumber;
|
||||||
} CStoreScanDescData;
|
} CStoreScanDescData;
|
||||||
|
|
||||||
typedef struct CStoreScanDescData *CStoreScanDesc;
|
typedef struct CStoreScanDescData *CStoreScanDesc;
|
||||||
|
@ -114,7 +120,10 @@ static bool ConditionalLockRelationWithTimeout(Relation rel, LOCKMODE lockMode,
|
||||||
int timeout, int retryInterval);
|
int timeout, int retryInterval);
|
||||||
static void LogRelationStats(Relation rel, int elevel);
|
static void LogRelationStats(Relation rel, int elevel);
|
||||||
static void TruncateCStore(Relation rel, int elevel);
|
static void TruncateCStore(Relation rel, int elevel);
|
||||||
|
static HeapTuple ColumnarSlotCopyHeapTuple(TupleTableSlot *slot);
|
||||||
|
|
||||||
|
/* Custom tuple slot ops used for columnar. Initialized in cstore_tableam_init(). */
|
||||||
|
TupleTableSlotOps TTSOpsColumnar;
|
||||||
|
|
||||||
static List *
|
static List *
|
||||||
RelationColumnList(Relation rel)
|
RelationColumnList(Relation rel)
|
||||||
|
@ -148,7 +157,7 @@ RelationColumnList(Relation rel)
|
||||||
static const TupleTableSlotOps *
|
static const TupleTableSlotOps *
|
||||||
cstore_slot_callbacks(Relation relation)
|
cstore_slot_callbacks(Relation relation)
|
||||||
{
|
{
|
||||||
return &TTSOpsVirtual;
|
return &TTSOpsColumnar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -313,6 +322,20 @@ cstore_getnextslot(TableScanDesc sscan, ScanDirection direction, TupleTableSlot
|
||||||
}
|
}
|
||||||
|
|
||||||
ExecStoreVirtualTuple(slot);
|
ExecStoreVirtualTuple(slot);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set slot's item pointer block & offset to non-zero. These are
|
||||||
|
* used just for sorting in acquire_sample_rows(), so rowNumber
|
||||||
|
* is good enough. See ColumnarSlotCopyHeapTuple for more info.
|
||||||
|
*
|
||||||
|
* offset is 16-bits, so use the first 15 bits for offset and
|
||||||
|
* rest as block number.
|
||||||
|
*/
|
||||||
|
ItemPointerSetBlockNumber(&(slot->tts_tid), scan->rowNumber / (32 * 1024) + 1);
|
||||||
|
ItemPointerSetOffsetNumber(&(slot->tts_tid), scan->rowNumber % (32 * 1024) + 1);
|
||||||
|
|
||||||
|
scan->rowNumber++;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1172,6 +1195,9 @@ cstore_tableam_init()
|
||||||
object_access_hook = CStoreTableAMObjectAccessHook;
|
object_access_hook = CStoreTableAMObjectAccessHook;
|
||||||
|
|
||||||
cstore_customscan_init();
|
cstore_customscan_init();
|
||||||
|
|
||||||
|
TTSOpsColumnar = TTSOpsVirtual;
|
||||||
|
TTSOpsColumnar.copy_heap_tuple = ColumnarSlotCopyHeapTuple;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1182,6 +1208,31 @@ cstore_tableam_finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Implementation of TupleTableSlotOps.copy_heap_tuple for TTSOpsColumnar.
|
||||||
|
*/
|
||||||
|
static HeapTuple
|
||||||
|
ColumnarSlotCopyHeapTuple(TupleTableSlot *slot)
|
||||||
|
{
|
||||||
|
Assert(!TTS_EMPTY(slot));
|
||||||
|
|
||||||
|
HeapTuple tuple = heap_form_tuple(slot->tts_tupleDescriptor,
|
||||||
|
slot->tts_values,
|
||||||
|
slot->tts_isnull);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need to set item pointer, since implementation of ANALYZE
|
||||||
|
* requires it. See the qsort in acquire_sample_rows() and
|
||||||
|
* also compare_rows in backend/commands/analyze.c.
|
||||||
|
*
|
||||||
|
* slot->tts_tid is filled in cstore_getnextslot.
|
||||||
|
*/
|
||||||
|
tuple->t_self = slot->tts_tid;
|
||||||
|
|
||||||
|
return tuple;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Implements object_access_hook. One of the places this is called is just
|
* Implements object_access_hook. One of the places this is called is just
|
||||||
* before dropping an object, which allows us to clean-up resources for
|
* before dropping an object, which allows us to clean-up resources for
|
||||||
|
|
|
@ -17,3 +17,9 @@ SELECT count(*) FROM pg_stats WHERE tablename='contestant_compressed';
|
||||||
6
|
6
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
-- ANALYZE a table with lots of data to trigget qsort in analyze.c
|
||||||
|
CREATE TABLE test_analyze(a int, b text, c char) USING columnar;
|
||||||
|
INSERT INTO test_analyze SELECT floor(i / 1000), floor(i / 10)::text, 4 FROM generate_series(1, 100000) i;
|
||||||
|
INSERT INTO test_analyze SELECT floor(i / 2), floor(i / 10)::text, 5 FROM generate_series(1000, 110000) i;
|
||||||
|
ANALYZE test_analyze;
|
||||||
|
DROP TABLE test_analyze;
|
||||||
|
|
|
@ -9,3 +9,11 @@ SELECT count(*) FROM pg_stats WHERE tablename='contestant';
|
||||||
-- ANALYZE compressed table
|
-- ANALYZE compressed table
|
||||||
ANALYZE contestant_compressed;
|
ANALYZE contestant_compressed;
|
||||||
SELECT count(*) FROM pg_stats WHERE tablename='contestant_compressed';
|
SELECT count(*) FROM pg_stats WHERE tablename='contestant_compressed';
|
||||||
|
|
||||||
|
-- ANALYZE a table with lots of data to trigget qsort in analyze.c
|
||||||
|
CREATE TABLE test_analyze(a int, b text, c char) USING columnar;
|
||||||
|
INSERT INTO test_analyze SELECT floor(i / 1000), floor(i / 10)::text, 4 FROM generate_series(1, 100000) i;
|
||||||
|
INSERT INTO test_analyze SELECT floor(i / 2), floor(i / 10)::text, 5 FROM generate_series(1000, 110000) i;
|
||||||
|
|
||||||
|
ANALYZE test_analyze;
|
||||||
|
DROP TABLE test_analyze;
|
||||||
|
|
Loading…
Reference in New Issue