Skip to content

Commit 75cbaac

Browse files
Enable segmentwise recompression for nullable order by columns with firstlast metadata index
1 parent 644f669 commit 75cbaac

7 files changed

Lines changed: 355 additions & 30 deletions

File tree

tsl/src/compression/api.c

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -715,18 +715,21 @@ decompress_chunk_impl(Chunk *uncompressed_chunk, bool if_compressed)
715715
}
716716

717717
bool
718-
is_chunk_orderby_nonnullable(CompressionSettings *settings)
718+
is_chunk_orderby_nullhandling(CompressionSettings *settings)
719719
{
720720
int num_orderby = ts_array_length(settings->fd.orderby);
721721
const char *attname;
722722
int attnum;
723723
for (int i = 1; i <= num_orderby; i++)
724724
{
725-
attname = ts_array_get_element_text(settings->fd.orderby, i);
726-
attnum = get_attnum(settings->fd.relid, attname);
727-
if (!AttributeNumberIsValid(attnum) || !ts_get_attnotnull(settings->fd.relid, attnum))
725+
if (orderby_sparse_kind(settings, i) != ORDERBY_SPARSE_FIRSTLAST)
728726
{
729-
return false;
727+
attname = ts_array_get_element_text(settings->fd.orderby, i);
728+
attnum = get_attnum(settings->fd.relid, attname);
729+
if (!AttributeNumberIsValid(attnum) || !ts_get_attnotnull(settings->fd.relid, attnum))
730+
{
731+
return false;
732+
}
730733
}
731734
}
732735
return true;
@@ -777,19 +780,18 @@ recompress_chunk_impl(Chunk *chunk, bool recompress)
777780

778781
/* #9444: do not recompress when order by columns are nullable, do segmentwise
779782
* decompress/compress instead. It is due to compression min/max metadata not handling
780-
* NULLs. When we implement chunks with min/max NULL-handling metadata, this restriction can
781-
* be lifted.
783+
* NULLs. This restriction is lifted with first/last metadata index.
782784
*/
783-
bool nullable_orderby = !is_chunk_orderby_nonnullable(chunk_settings);
784-
if (nullable_orderby)
785+
bool orderby_not_handling_nulls = !is_chunk_orderby_nullhandling(chunk_settings);
786+
if (orderby_not_handling_nulls)
785787
{
786788
elog(ts_guc_debug_compression_path_info ? INFO : DEBUG1,
787-
"in-memory recompression is disabled due to nullable order by, "
789+
"in-memory recompression is disabled due to nullable order by with no firstlast, "
788790
"performing segmentwise decompress/compress on chunk \"%s.%s\"",
789791
NameStr(chunk->fd.schema_name),
790792
NameStr(chunk->fd.table_name));
791793
}
792-
recompress_chunk_segmentwise_impl(chunk, nullable_orderby);
794+
recompress_chunk_segmentwise_impl(chunk, orderby_not_handling_nulls);
793795
recompressed = true;
794796
}
795797
else

tsl/src/compression/api.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,4 @@ extern void compression_chunk_size_catalog_insert(int32 src_chunk_id, const Rela
3131
int64 rowcnt_frozen);
3232
extern Datum tsl_estimate_compressed_batch_size(PG_FUNCTION_ARGS);
3333

34-
extern bool is_chunk_orderby_nonnullable(CompressionSettings *settings);
34+
extern bool is_chunk_orderby_nullhandling(CompressionSettings *settings);

tsl/src/compression/compression_dml.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ typedef struct tuple_filtering_constraints
3131
bool vectorized_filtering;
3232
} tuple_filtering_constraints;
3333

34-
bool slot_key_test(TupleTableSlot *slot, ScanKey skey);
34+
bool slot_key_test(TupleTableSlot *slot, ScanKey skey, bool nulls_first);
3535

3636
ScanKeyData *build_mem_scankeys_from_slot(Oid ht_relid, CompressionSettings *settings,
3737
Relation out_rel,

tsl/src/compression/compression_scankey.c

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,15 @@ static bool create_segment_filter_scankey(Relation in_rel, char *segment_filter_
2727
*
2828
* Unlike HeapKeyTest, this function takes into account SK_ISNULL
2929
* and works correctly when looking for null values.
30+
*
31+
* If slot attribute is NULL and key is NOT NULL,
32+
* (key >= NULL) returns True for nulls_first
33+
* and (key <= NULL) returns True for !nulls_first (i.e. for NULLS LAST).
3034
*/
3135
bool
32-
slot_key_test(TupleTableSlot *compressed_slot, ScanKey key)
36+
slot_key_test(TupleTableSlot *compressed_slot, ScanKey key, bool nulls_first)
3337
{
34-
/* No need to get the datum if we are only checking for NULLs */
38+
/* No need to get the datum if we are only checking for NULL key */
3539
if (key->sk_flags & SK_ISNULL)
3640
{
3741
return slot_attisnull(compressed_slot, key->sk_attno);
@@ -43,6 +47,20 @@ slot_key_test(TupleTableSlot *compressed_slot, ScanKey key)
4347

4448
if (is_null)
4549
{
50+
/* NULL < key i.e. NULL sorts before key argument */
51+
if (nulls_first && (key->sk_strategy == BTLessStrategyNumber ||
52+
key->sk_strategy == BTLessEqualStrategyNumber))
53+
{
54+
return true;
55+
}
56+
57+
/* NULL > key i.e. NULL sorts after key argument */
58+
if (!nulls_first && (key->sk_strategy == BTGreaterStrategyNumber ||
59+
key->sk_strategy == BTGreaterEqualStrategyNumber))
60+
{
61+
return true;
62+
}
63+
4664
return false;
4765
}
4866

tsl/src/compression/recompress.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -122,16 +122,16 @@ tsl_recompress_chunk_segmentwise(PG_FUNCTION_ARGS)
122122
"compression with no "
123123
"order by")));
124124
}
125-
bool nullable_orderby = !is_chunk_orderby_nonnullable(settings);
126-
if (nullable_orderby)
125+
bool orderby_not_handling_nulls = !is_chunk_orderby_nullhandling(settings);
126+
if (orderby_not_handling_nulls)
127127
{
128128
elog(ts_guc_debug_compression_path_info ? INFO : DEBUG1,
129-
"in-memory recompression is disabled due to nullable order by, "
129+
"in-memory recompression is disabled due to nullable order by with no firstlast, "
130130
"performing segmentwise decompress/compress on chunk \"%s.%s\"",
131131
NameStr(chunk->fd.schema_name),
132132
NameStr(chunk->fd.table_name));
133133
}
134-
recompress_chunk_segmentwise_impl(chunk, nullable_orderby);
134+
recompress_chunk_segmentwise_impl(chunk, orderby_not_handling_nulls);
135135
}
136136

137137
PG_RETURN_OID(uncompressed_relid);
@@ -1063,6 +1063,7 @@ update_orderby_scankeys(Datum *values, bool *isnulls, int num_segmentby, int num
10631063
static enum Batch_match_result
10641064
handle_null_scan(int key_flags, bool nulls_first, enum Batch_match_result result)
10651065
{
1066+
/* uncompressed tuple key is NULL */
10661067
if (key_flags & SK_ISNULL)
10671068
{
10681069
return nulls_first ? Tuple_before : Tuple_after;
@@ -1086,18 +1087,17 @@ match_tuple_batch(TupleTableSlot *compressed_slot, int num_orderby, ScanKey orde
10861087
if (num_orderby >= 1)
10871088
{
10881089
ScanKey key = &orderby_scankeys[0];
1089-
if (!slot_key_test(compressed_slot, key))
1090+
if (!slot_key_test(compressed_slot, key, nulls_first[0]))
10901091
{
10911092
return handle_null_scan(key->sk_flags, nulls_first[0], Tuple_before);
10921093
}
10931094

10941095
key = &orderby_scankeys[1];
1095-
if (!slot_key_test(compressed_slot, key))
1096+
if (!slot_key_test(compressed_slot, key, nulls_first[0]))
10961097
{
10971098
return handle_null_scan(key->sk_flags, nulls_first[0], Tuple_after);
10981099
}
10991100
}
1100-
11011101
return Tuple_match;
11021102
}
11031103

0 commit comments

Comments
 (0)