Skip to content

Commit 2f13375

Browse files
committed
Use brief explain stats
Use a more compact and easy to read version for the decompression and arrow array cache stats and simplify the code.
1 parent 4316f2c commit 2f13375

17 files changed

+521
-631
lines changed

tsl/src/hypercore/arrow_cache_explain.c

Lines changed: 45 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -61,43 +61,12 @@ standard_ExplainOneQuery(Query *query, int cursorOptions, IntoClause *into, Expl
6161
}
6262
#endif
6363

64-
static struct
65-
{
66-
const char *hits_text; /* Number of cache hits */
67-
const char *miss_text; /* Number of cache misses */
68-
const char *evict_text; /* Number of cache evictions */
69-
const char *decompress_text; /* Number of arrays decompressed */
70-
const char *decompress_calls_text; /* Number of calls to decompress an array */
71-
} format_texts[] = {
72-
[EXPLAIN_FORMAT_TEXT] = {
73-
.hits_text = "Array Cache Hits",
74-
.miss_text = "Array Cache Misses",
75-
.evict_text = "Array Cache Evictions",
76-
.decompress_text = "Array Decompressions",
77-
.decompress_calls_text = "Array Decompression Calls",
78-
},
79-
[EXPLAIN_FORMAT_XML]= {
80-
.hits_text = "hits",
81-
.miss_text = "misses",
82-
.evict_text = "evictions",
83-
.decompress_text = "decompressions",
84-
.decompress_calls_text = "decompression calls",
85-
},
86-
[EXPLAIN_FORMAT_JSON] = {
87-
.hits_text = "hits",
88-
.miss_text = "misses",
89-
.evict_text = "evictions",
90-
.decompress_text = "decompressions",
91-
.decompress_calls_text = "decompression calls",
92-
},
93-
[EXPLAIN_FORMAT_YAML] = {
94-
.hits_text = "hits",
95-
.miss_text = "misses",
96-
.evict_text = "evictions",
97-
.decompress_text = "decompressions",
98-
.decompress_calls_text = "decompression calls",
99-
},
100-
};
64+
#define APPEND_IF_POSITIVE(INFO, FMT, VAL) \
65+
do \
66+
{ \
67+
if ((VAL) > 0) \
68+
appendStringInfo((INFO), " " FMT, (long long) (VAL)); \
69+
} while (0)
10170

10271
static void
10372
explain_decompression(Query *query, int cursorOptions, IntoClause *into, ExplainState *es,
@@ -106,33 +75,45 @@ explain_decompression(Query *query, int cursorOptions, IntoClause *into, Explain
10675
standard_ExplainOneQuery(query, cursorOptions, into, es, queryString, params, queryEnv);
10776
if (decompress_cache_print)
10877
{
109-
Assert(es->format < sizeof(format_texts) / sizeof(*format_texts));
110-
111-
ExplainOpenGroup("Array cache", "Arrow Array Cache", true, es);
112-
ExplainPropertyInteger(format_texts[es->format].hits_text,
113-
NULL,
114-
decompress_cache_stats.hits,
115-
es);
116-
ExplainPropertyInteger(format_texts[es->format].miss_text,
117-
NULL,
118-
decompress_cache_stats.misses,
119-
es);
120-
ExplainPropertyInteger(format_texts[es->format].evict_text,
121-
NULL,
122-
decompress_cache_stats.evictions,
123-
es);
124-
ExplainPropertyInteger(format_texts[es->format].decompress_text,
125-
NULL,
126-
decompress_cache_stats.decompressions,
127-
es);
128-
129-
if (es->verbose)
130-
ExplainPropertyInteger(format_texts[es->format].decompress_calls_text,
131-
NULL,
132-
decompress_cache_stats.decompress_calls,
133-
es);
134-
135-
ExplainCloseGroup("Array cache", "Arrow Array Cache", true, es);
78+
const bool has_decompress_data = decompress_cache_stats.decompressions > 0 ||
79+
decompress_cache_stats.decompress_calls > 0;
80+
const bool has_cache_data = decompress_cache_stats.hits > 0 ||
81+
decompress_cache_stats.misses > 0 ||
82+
decompress_cache_stats.evictions > 0;
83+
if (has_decompress_data || has_cache_data)
84+
{
85+
if (es->format == EXPLAIN_FORMAT_TEXT)
86+
{
87+
appendStringInfoString(es->str, "Array:");
88+
if (has_cache_data)
89+
appendStringInfoString(es->str, " cache");
90+
APPEND_IF_POSITIVE(es->str, "hits=%lld", decompress_cache_stats.hits);
91+
APPEND_IF_POSITIVE(es->str, "misses=%lld", decompress_cache_stats.misses);
92+
APPEND_IF_POSITIVE(es->str, "evictions=%lld", decompress_cache_stats.evictions);
93+
if (has_decompress_data)
94+
appendStringInfoString(es->str, ", decompress");
95+
APPEND_IF_POSITIVE(es->str, "count=%lld", decompress_cache_stats.decompressions);
96+
APPEND_IF_POSITIVE(es->str, "calls=%lld", decompress_cache_stats.decompress_calls);
97+
appendStringInfoChar(es->str, '\n');
98+
}
99+
else
100+
{
101+
ExplainOpenGroup("Array Cache", "Arrow Array Cache", true, es);
102+
ExplainPropertyInteger("hits", NULL, decompress_cache_stats.hits, es);
103+
ExplainPropertyInteger("misses", NULL, decompress_cache_stats.misses, es);
104+
ExplainPropertyInteger("evictions", NULL, decompress_cache_stats.evictions, es);
105+
ExplainCloseGroup("Array Cache", "Arrow Array Cache", true, es);
106+
107+
ExplainOpenGroup("Array Decompress", "Arrow Array Decompress", true, es);
108+
ExplainPropertyInteger("count", NULL, decompress_cache_stats.decompressions, es);
109+
if (es->verbose)
110+
ExplainPropertyInteger("calls",
111+
NULL,
112+
decompress_cache_stats.decompress_calls,
113+
es);
114+
ExplainCloseGroup("Array Decompress", "Arrow Array Decompress", true, es);
115+
}
116+
}
136117

137118
decompress_cache_print = false;
138119
memset(&decompress_cache_stats, 0, sizeof(struct DecompressCacheStats));

tsl/test/expected/hypercore_columnar.out

Lines changed: 42 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,23 @@
99
-- emitted plan. This is intended to be used when the structure of the
1010
-- plan is important, but not the specific chunks scanned nor the
1111
-- number of heap fetches, rows, loops, etc.
12+
create function anonymize(ln text) returns text language plpgsql as
13+
$$
14+
begin
15+
ln := regexp_replace(ln, '_hyper_\d+_\d+_chunk', '_hyper_I_N_chunk', 1, 0);
16+
ln := regexp_replace(ln, 'Heap Fetches: \d+', 'Heap Fetches: N');
17+
ln := regexp_replace(ln, 'Workers Launched: \d+', 'Workers Launched: N');
18+
ln := regexp_replace(ln, 'actual rows=\d+ loops=\d+', 'actual rows=N loops=N');
19+
20+
if trim(both from ln) like 'Array: %' then
21+
ln := regexp_replace(ln, 'hits=\d+', 'hits=N');
22+
ln := regexp_replace(ln, 'misses=\d+', 'misses=N');
23+
ln := regexp_replace(ln, 'count=\d+', 'count=N');
24+
ln := regexp_replace(ln, 'calls=\d+', 'calls=N');
25+
end if;
26+
return ln;
27+
end
28+
$$;
1229
create function explain_analyze_anonymize(text) returns setof text
1330
language plpgsql as
1431
$$
@@ -18,17 +35,11 @@ begin
1835
for ln in
1936
execute format('explain (analyze, costs off, summary off, timing off, decompress_cache_stats) %s', $1)
2037
loop
21-
if trim(both from ln) like 'Group Key:%' then
22-
continue;
23-
end if;
24-
ln := regexp_replace(ln, 'Array Cache Hits: \d+', 'Array Cache Hits: N');
25-
ln := regexp_replace(ln, 'Array Cache Misses: \d+', 'Array Cache Misses: N');
26-
ln := regexp_replace(ln, 'Array Cache Evictions: \d+', 'Array Cache Evictions: N');
27-
ln := regexp_replace(ln, 'Heap Fetches: \d+', 'Heap Fetches: N');
28-
ln := regexp_replace(ln, 'Workers Launched: \d+', 'Workers Launched: N');
29-
ln := regexp_replace(ln, 'actual rows=\d+ loops=\d+', 'actual rows=N loops=N');
30-
ln := regexp_replace(ln, '_hyper_\d+_\d+_chunk', '_hyper_I_N_chunk', 1, 0);
31-
return next ln;
38+
if trim(both from ln) like 'Group Key:%' then
39+
continue;
40+
end if;
41+
42+
return next anonymize(ln);
3243
end loop;
3344
end;
3445
$$;
@@ -41,14 +52,10 @@ begin
4152
for ln in
4253
execute format('explain (costs off, summary off, timing off) %s', $1)
4354
loop
44-
ln := regexp_replace(ln, 'Array Cache Hits: \d+', 'Array Cache Hits: N');
45-
ln := regexp_replace(ln, 'Array Cache Misses: \d+', 'Array Cache Misses: N');
46-
ln := regexp_replace(ln, 'Array Cache Evictions: \d+', 'Array Cache Evictions: N');
47-
ln := regexp_replace(ln, 'Heap Fetches: \d+', 'Heap Fetches: N');
48-
ln := regexp_replace(ln, 'Workers Launched: \d+', 'Workers Launched: N');
49-
ln := regexp_replace(ln, 'actual rows=\d+ loops=\d+', 'actual rows=N loops=N');
50-
ln := regexp_replace(ln, '_hyper_\d+_\d+_chunk', '_hyper_I_N_chunk', 1, 0);
51-
return next ln;
55+
if trim(both from ln) like 'Group Key:%' then
56+
continue;
57+
end if;
58+
return next anonymize(ln);
5259
end loop;
5360
end;
5461
$$;
@@ -101,11 +108,8 @@ $$, :'chunk'));
101108
Scankey: (device < 4)
102109
Vectorized Filter: (location = 2)
103110
Rows Removed by Filter: 16
104-
Array Cache Hits: N
105-
Array Cache Misses: N
106-
Array Cache Evictions: N
107-
Array Decompressions: 3
108-
(9 rows)
111+
Array: cache misses=N, decompress count=N calls=N
112+
(6 rows)
109113

110114
-- Save away all data from the chunk so that we can compare.
111115
create table saved as select * from :chunk;
@@ -136,11 +140,8 @@ $$, :'chunk'));
136140
-> Custom Scan (ColumnarScan) on _hyper_I_N_chunk (actual rows=N loops=N)
137141
Vectorized Filter: (humidity > '110'::double precision)
138142
Rows Removed by Filter: 204
139-
Array Cache Hits: N
140-
Array Cache Misses: N
141-
Array Cache Evictions: N
142-
Array Decompressions: 30
143-
(8 rows)
143+
Array: cache misses=N, decompress count=N calls=N
144+
(5 rows)
144145

145146
select count(*) from :chunk where humidity > 110;
146147
count
@@ -159,11 +160,8 @@ $$, :'chunk'));
159160
-> Custom Scan (ColumnarScan) on _hyper_I_N_chunk (actual rows=N loops=N)
160161
Vectorized Filter: (humidity > '50'::double precision)
161162
Rows Removed by Filter: 87
162-
Array Cache Hits: N
163-
Array Cache Misses: N
164-
Array Cache Evictions: N
165-
Array Decompressions: 30
166-
(8 rows)
163+
Array: cache misses=N, decompress count=N calls=N
164+
(5 rows)
167165

168166
select lhs.count, rhs.count
169167
from (select count(*) from :chunk where humidity > 50) lhs,
@@ -194,11 +192,8 @@ $$, :'chunk'));
194192
-> Custom Scan (ColumnarScan) on _hyper_I_N_chunk (actual rows=N loops=N)
195193
Filter: (temp > '50'::numeric)
196194
Rows Removed by Filter: 204
197-
Array Cache Hits: N
198-
Array Cache Misses: N
199-
Array Cache Evictions: N
200-
Array Decompressions: 30
201-
(8 rows)
195+
Array: cache misses=N, decompress count=N calls=N
196+
(5 rows)
202197

203198
select count(*) from :chunk where temp > 50;
204199
count
@@ -216,11 +211,8 @@ $$, :'chunk'));
216211
-> Custom Scan (ColumnarScan) on _hyper_I_N_chunk (actual rows=N loops=N)
217212
Filter: (temp > '20'::numeric)
218213
Rows Removed by Filter: 98
219-
Array Cache Hits: N
220-
Array Cache Misses: N
221-
Array Cache Evictions: N
222-
Array Decompressions: 30
223-
(8 rows)
214+
Array: cache misses=N, decompress count=N calls=N
215+
(5 rows)
224216

225217
select lhs.count, rhs.count
226218
from (select count(*) from :chunk where temp > 20) lhs,
@@ -251,11 +243,8 @@ select count(*) from :chunk where humidity > 40 and temp > 20;
251243
Filter: (temp > '20'::numeric)
252244
Rows Removed by Filter: 132
253245
Vectorized Filter: (humidity > '40'::double precision)
254-
Array Cache Hits: 0
255-
Array Cache Misses: 30
256-
Array Cache Evictions: 0
257-
Array Decompressions: 60
258-
(9 rows)
246+
Array: cache misses=30, decompress count=60 calls=165
247+
(6 rows)
259248

260249
select count(*) from :chunk where humidity > 40 and temp > 20;
261250
count
@@ -284,11 +273,8 @@ $$, :'chunk'));
284273
Rows Removed by Filter: 3
285274
Scankey: (device = 3)
286275
Vectorized Filter: (humidity > '40'::double precision)
287-
Array Cache Hits: N
288-
Array Cache Misses: N
289-
Array Cache Evictions: N
290-
Array Decompressions: 2
291-
(10 rows)
276+
Array: cache misses=N, decompress count=N calls=N
277+
(7 rows)
292278

293279
select count(*) from :chunk where humidity > 40 and temp > 20 and device = 3;
294280
count
@@ -318,11 +304,8 @@ $$, :'chunk'));
318304
-> Seq Scan on _hyper_I_N_chunk (actual rows=N loops=N)
319305
Filter: (device < 4)
320306
Rows Removed by Filter: 184
321-
Array Cache Hits: N
322-
Array Cache Misses: N
323-
Array Cache Evictions: N
324-
Array Decompressions: 96
325-
(11 rows)
307+
Array: cache misses=N, decompress count=N calls=N
308+
(8 rows)
326309

327310
drop table readings;
328311
drop table saved;

tsl/test/expected/hypercore_copy.out

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,23 @@
1414
-- emitted plan. This is intended to be used when the structure of the
1515
-- plan is important, but not the specific chunks scanned nor the
1616
-- number of heap fetches, rows, loops, etc.
17+
create function anonymize(ln text) returns text language plpgsql as
18+
$$
19+
begin
20+
ln := regexp_replace(ln, '_hyper_\d+_\d+_chunk', '_hyper_I_N_chunk', 1, 0);
21+
ln := regexp_replace(ln, 'Heap Fetches: \d+', 'Heap Fetches: N');
22+
ln := regexp_replace(ln, 'Workers Launched: \d+', 'Workers Launched: N');
23+
ln := regexp_replace(ln, 'actual rows=\d+ loops=\d+', 'actual rows=N loops=N');
24+
25+
if trim(both from ln) like 'Array: %' then
26+
ln := regexp_replace(ln, 'hits=\d+', 'hits=N');
27+
ln := regexp_replace(ln, 'misses=\d+', 'misses=N');
28+
ln := regexp_replace(ln, 'count=\d+', 'count=N');
29+
ln := regexp_replace(ln, 'calls=\d+', 'calls=N');
30+
end if;
31+
return ln;
32+
end
33+
$$;
1734
create function explain_analyze_anonymize(text) returns setof text
1835
language plpgsql as
1936
$$
@@ -23,17 +40,11 @@ begin
2340
for ln in
2441
execute format('explain (analyze, costs off, summary off, timing off, decompress_cache_stats) %s', $1)
2542
loop
26-
if trim(both from ln) like 'Group Key:%' then
27-
continue;
28-
end if;
29-
ln := regexp_replace(ln, 'Array Cache Hits: \d+', 'Array Cache Hits: N');
30-
ln := regexp_replace(ln, 'Array Cache Misses: \d+', 'Array Cache Misses: N');
31-
ln := regexp_replace(ln, 'Array Cache Evictions: \d+', 'Array Cache Evictions: N');
32-
ln := regexp_replace(ln, 'Heap Fetches: \d+', 'Heap Fetches: N');
33-
ln := regexp_replace(ln, 'Workers Launched: \d+', 'Workers Launched: N');
34-
ln := regexp_replace(ln, 'actual rows=\d+ loops=\d+', 'actual rows=N loops=N');
35-
ln := regexp_replace(ln, '_hyper_\d+_\d+_chunk', '_hyper_I_N_chunk', 1, 0);
36-
return next ln;
43+
if trim(both from ln) like 'Group Key:%' then
44+
continue;
45+
end if;
46+
47+
return next anonymize(ln);
3748
end loop;
3849
end;
3950
$$;
@@ -46,14 +57,10 @@ begin
4657
for ln in
4758
execute format('explain (costs off, summary off, timing off) %s', $1)
4859
loop
49-
ln := regexp_replace(ln, 'Array Cache Hits: \d+', 'Array Cache Hits: N');
50-
ln := regexp_replace(ln, 'Array Cache Misses: \d+', 'Array Cache Misses: N');
51-
ln := regexp_replace(ln, 'Array Cache Evictions: \d+', 'Array Cache Evictions: N');
52-
ln := regexp_replace(ln, 'Heap Fetches: \d+', 'Heap Fetches: N');
53-
ln := regexp_replace(ln, 'Workers Launched: \d+', 'Workers Launched: N');
54-
ln := regexp_replace(ln, 'actual rows=\d+ loops=\d+', 'actual rows=N loops=N');
55-
ln := regexp_replace(ln, '_hyper_\d+_\d+_chunk', '_hyper_I_N_chunk', 1, 0);
56-
return next ln;
60+
if trim(both from ln) like 'Group Key:%' then
61+
continue;
62+
end if;
63+
return next anonymize(ln);
5764
end loop;
5865
end;
5966
$$;

0 commit comments

Comments
 (0)