Skip to content

Commit ee162aa

Browse files
authored
perf(v2): tune parquet row iterator batching (#3726)
1 parent a2ca38d commit ee162aa

File tree

3 files changed

+40
-17
lines changed

3 files changed

+40
-17
lines changed

pkg/experiment/query_backend/query_profile_entry.go

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,20 @@ import (
1313
"github.com/grafana/pyroscope/pkg/phlaredb/tsdb/index"
1414
)
1515

16+
// As we expect rows to be very small, we want to fetch a bigger
17+
// batch of rows at once to amortize the latency of reading.
18+
const bigBatchSize = 2 << 10
19+
20+
type ProfileEntry struct {
21+
RowNum int64
22+
Timestamp model.Time
23+
Fingerprint model.Fingerprint
24+
Labels phlaremodel.Labels
25+
Partition uint64
26+
}
27+
28+
func (e ProfileEntry) RowNumber() int64 { return e.RowNum }
29+
1630
func profileEntryIterator(q *queryContext, groupBy ...string) (iter.Iterator[ProfileEntry], error) {
1731
series, err := getSeriesLabels(q.ds.Index(), q.req.matchers, groupBy...)
1832
if err != nil {
@@ -28,7 +42,7 @@ func profileEntryIterator(q *queryContext, groupBy ...string) (iter.Iterator[Pro
2842

2943
buf := make([][]parquet.Value, 3)
3044
entries := iter.NewAsyncBatchIterator[*parquetquery.IteratorResult, ProfileEntry](
31-
results, 128,
45+
results, bigBatchSize,
3246
func(r *parquetquery.IteratorResult) ProfileEntry {
3347
buf = r.Columns(buf,
3448
schemav1.SeriesIndexColumnName,
@@ -48,16 +62,6 @@ func profileEntryIterator(q *queryContext, groupBy ...string) (iter.Iterator[Pro
4862
return entries, nil
4963
}
5064

51-
type ProfileEntry struct {
52-
RowNum int64
53-
Timestamp model.Time
54-
Fingerprint model.Fingerprint
55-
Labels phlaremodel.Labels
56-
Partition uint64
57-
}
58-
59-
func (e ProfileEntry) RowNumber() int64 { return e.RowNum }
60-
6165
type seriesLabels struct {
6266
fingerprint model.Fingerprint
6367
labels phlaremodel.Labels

pkg/experiment/query_backend/query_time_series.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ func queryTimeSeries(q *queryContext, query *queryv1.Query) (r *queryv1.Report,
4040
return nil, err
4141
}
4242

43-
rows := parquetquery.NewRepeatedRowIterator(q.ctx, entries, q.ds.Profiles().RowGroups(), column.ColumnIndex)
43+
rows := parquetquery.NewRepeatedRowIteratorBatchSize(q.ctx, entries, q.ds.Profiles().RowGroups(), bigBatchSize, column.ColumnIndex)
4444
defer runutil.CloseWithErrCapture(&err, rows, "failed to close column iterator")
4545

4646
builder := phlaremodel.NewTimeSeriesBuilder(query.TimeSeries.GroupBy...)

pkg/phlaredb/query/repeated.go

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,24 +38,43 @@ const (
3838
//
3939
// How many values we expect per a row, the upper boundary?
4040
repeatedRowColumnIteratorReadSize = 2 << 10
41+
42+
// Batch size specifies how many rows to read from a column at once.
43+
// Note that the batched rows are buffered in-memory but do not reference
44+
// the pages from which they were read.
45+
//
46+
// The default value is extremely conservative, as in most cases, rows are
47+
// quite large (e.g., profile samples). Given that we run many queries
48+
// concurrently, the memory waste outweighs the benefits of the "read-ahead"
49+
// optimization that batching is intended to provide.
50+
//
51+
// However, in cases where the rows are small (such as in time series),
52+
// the value should be increased significantly.
53+
defaultBatchSize = 4
4154
)
4255

4356
func NewRepeatedRowIterator[T any](
4457
ctx context.Context,
4558
rows iter.Iterator[T],
4659
rowGroups []parquet.RowGroup,
4760
columns ...int,
61+
) iter.Iterator[RepeatedRow[T]] {
62+
return NewRepeatedRowIteratorBatchSize(ctx, rows, rowGroups, defaultBatchSize, columns...)
63+
}
64+
65+
func NewRepeatedRowIteratorBatchSize[T any](
66+
ctx context.Context,
67+
rows iter.Iterator[T],
68+
rowGroups []parquet.RowGroup,
69+
batchSize int64,
70+
columns ...int,
4871
) iter.Iterator[RepeatedRow[T]] {
4972
rows, rowNumbers := iter.Tee(rows)
5073
return &repeatedRowIterator[T]{
5174
rows: rows,
5275
columns: NewMultiColumnIterator(ctx,
5376
WrapWithRowNumber(rowNumbers),
54-
// Batch size specifies how many rows to be read
55-
// from a column at once. Note that the batched rows
56-
// are buffered in-memory, but not reference pages
57-
// they were read from.
58-
4,
77+
int(batchSize),
5978
rowGroups,
6079
columns...,
6180
),

0 commit comments

Comments
 (0)