[ 
https://issues.apache.org/jira/browse/CALCITE-7805?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Frank Chen updated CALCITE-7805:
--------------------------------
    Description: 
[CALCITE-7782|https://issues.apache.org/jira/browse/CALCITE-7782] eliminated 
quadratic operand-list copying while validating large ARRAY and MAP 
constructors, allowing a 1,000,000-element string ARRAY to complete. Planning 
remains allocation-heavy: Druid's benchmark allocates approximately 15.4 GB and 
takes approximately 7.8 seconds for one million string literals. Allocation is 
cumulative bytes per operation, not retained or peak heap.

h2. Reproducer

{code:sql}
SELECT string1
FROM foo
WHERE string1 IN ('1', '2', ..., '1000000')
{code}

Druid rewrites this predicate to:

{code}
SCALAR_IN_ARRAY(string1, ARRAY['1', '2', ..., '1000000'])
{code}

The benchmark is {{InPlanningBenchmark.queryStringInSqlPlanOnly}}.

h2. Work items

The remaining allocation sources are tracked independently:

* [CALCITE-7806|https://issues.apache.org/jira/browse/CALCITE-7806] - Avoid 
resolving generated CAST calls during ARRAY validation.
* [CALCITE-7807|https://issues.apache.org/jira/browse/CALCITE-7807] - Reuse 
unchanged SQL types during least-restrictive inference.
* [CALCITE-7808|https://issues.apache.org/jira/browse/CALCITE-7808] - Cache 
recently created and decorated SQL types.
* [CALCITE-7809|https://issues.apache.org/jira/browse/CALCITE-7809] - Avoid 
copying unchanged SQL and Rex operands.
* [CALCITE-7810|https://issues.apache.org/jira/browse/CALCITE-7810] - Write Rex 
string literal digests directly.

Combined prototypes reduced allocation by approximately 70% in this Druid 
workload. Each sub-task contains its isolated measurement and scope.

  was:
CALCITE-7782 and [PR #5263|https://github.com/apache/calcite/pull/5263] 
eliminated quadratic operand-list copying while validating large ARRAY and MAP 
constructors. That correction allows a 1,000,000-element string ARRAY to 
complete instead of running for more than 20 minutes.

After that correction, validation is linear, but planning still creates many 
temporary objects for every string literal. In the benchmark below, planning a 
1,000,000-element string IN expression allocates approximately 15.4 GB during 
one operation and takes approximately 7.8 seconds.

The allocation values below are cumulative allocation during one planning 
operation, not retained memory or peak heap usage.

h2. Reproducer

Apache Druid exposes the remaining allocation through a large string IN 
predicate:

{code:sql}
SELECT string1
FROM foo
WHERE string1 IN ('1', '2', ..., '1000000')
{code}

Druid rewrites the predicate to an expression containing a string ARRAY:

{code}
SCALAR_IN_ARRAY(string1, ARRAY['1', '2', ..., '1000000'])
{code}

The benchmark is {{InPlanningBenchmark.queryStringInSqlPlanOnly}}.

Parameters:
* {{inSubQueryThreshold = 2147483647}}
* {{rowsPerSegment = 500000}}
* 2 JMH forks
* 2 one-second warmup iterations per fork
* 5 one-second measurement iterations per fork
* GC profiler enabled
* Temurin 25.0.4.1

The Calcite baseline is commit {{38413ece6}}, which includes the merged 
CALCITE-7782 change.

h2. Proposed delivery

The implementation is split into five independently reviewable sub-tasks:

# [CALCITE-7806|https://issues.apache.org/jira/browse/CALCITE-7806] - Avoid 
resolving generated CAST calls during ARRAY validation.
# [CALCITE-7807|https://issues.apache.org/jira/browse/CALCITE-7807] - Reuse 
unchanged SQL types during least-restrictive inference.
# [CALCITE-7808|https://issues.apache.org/jira/browse/CALCITE-7808] - Cache 
recently created and decorated SQL types.
# [CALCITE-7809|https://issues.apache.org/jira/browse/CALCITE-7809] - Avoid 
copying unchanged SQL and Rex operands.
# [CALCITE-7810|https://issues.apache.org/jira/browse/CALCITE-7810] - Write Rex 
string literal digests directly.

Each sub-task links its corresponding pull request and can be reviewed and 
tested independently.

h2. Combined benchmark

When changes are stacked together, the benchmark shows about 70% allocation 
saving.

|| String literals || CALCITE-7782 baseline || All proposed changes || 
Allocation saved ||
| 100,000 | 1.522 GB/op | 0.445 GB/op | 1.077 GB/op (70.8%) |
| 1,000,000 | 15.418 GB/op | 4.556 GB/op | 10.862 GB/op (70.5%) |


For each change, the separated benchmark data is attached in their descriptions


> Reduce temporary object allocation when validating large string ARRAYs to 
> lower GC pressure
> -------------------------------------------------------------------------------------------
>
>                 Key: CALCITE-7805
>                 URL: https://issues.apache.org/jira/browse/CALCITE-7805
>             Project: Calcite
>          Issue Type: Improvement
>          Components: core
>    Affects Versions: 1.42.0
>            Reporter: Frank Chen
>            Priority: Major
>              Labels: pull-request-available
>
> [CALCITE-7782|https://issues.apache.org/jira/browse/CALCITE-7782] eliminated 
> quadratic operand-list copying while validating large ARRAY and MAP 
> constructors, allowing a 1,000,000-element string ARRAY to complete. Planning 
> remains allocation-heavy: Druid's benchmark allocates approximately 15.4 GB 
> and takes approximately 7.8 seconds for one million string literals. 
> Allocation is cumulative bytes per operation, not retained or peak heap.
> h2. Reproducer
> {code:sql}
> SELECT string1
> FROM foo
> WHERE string1 IN ('1', '2', ..., '1000000')
> {code}
> Druid rewrites this predicate to:
> {code}
> SCALAR_IN_ARRAY(string1, ARRAY['1', '2', ..., '1000000'])
> {code}
> The benchmark is {{InPlanningBenchmark.queryStringInSqlPlanOnly}}.
> h2. Work items
> The remaining allocation sources are tracked independently:
> * [CALCITE-7806|https://issues.apache.org/jira/browse/CALCITE-7806] - Avoid 
> resolving generated CAST calls during ARRAY validation.
> * [CALCITE-7807|https://issues.apache.org/jira/browse/CALCITE-7807] - Reuse 
> unchanged SQL types during least-restrictive inference.
> * [CALCITE-7808|https://issues.apache.org/jira/browse/CALCITE-7808] - Cache 
> recently created and decorated SQL types.
> * [CALCITE-7809|https://issues.apache.org/jira/browse/CALCITE-7809] - Avoid 
> copying unchanged SQL and Rex operands.
> * [CALCITE-7810|https://issues.apache.org/jira/browse/CALCITE-7810] - Write 
> Rex string literal digests directly.
> Combined prototypes reduced allocation by approximately 70% in this Druid 
> workload. Each sub-task contains its isolated measurement and scope.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to