FrankChen021 opened a new pull request, #5280:
URL: https://github.com/apache/calcite/pull/5280

   ## Jira Link
   
   [CALCITE-7805](https://issues.apache.org/jira/browse/CALCITE-7805)
   
   ## Changes Proposed
   
   Large string ARRAY validation creates generated CAST calls for operands 
whose inferred type differs from the common element type. These calls already 
use the built-in CAST operator, but the normal validation path resolves the 
operator again by name for every operand.
   
   Validate each generated CAST directly through its existing operator before 
replacing the operand. This preserves operand checks and validated-node type 
registration while avoiding repeated function lookup.
   
   The regression test also verifies the contract this optimization relies on: 
after `validateOperands` registers the generated CAST type, a later 
`deriveType` call reuses that cached type and performs no operator-table lookup.
   
   This branch is based directly on `main` at `38413ece6`, which includes the 
bulk operand replacement from CALCITE-7782. It is independent of the other 
allocation optimizations.
   
   ## Execution Path
   
   Before this change, Calcite creates each generated CAST with the built-in 
operator but does not immediately register its validated type:
   
   ```text
   Create built-in CAST node
     -> no validated type recorded
     -> later validator.deriveType(cast)
     -> SqlOperator.deriveType
     -> build operand and argument-type lists
     -> SqlUtil.lookupRoutine(...)
     -> search the operator table for "CAST"
     -> find the same built-in CAST operator
     -> validateOperands(...)
     -> store the validated type
   ```
   
   The expensive work is resolving an operator that is already known. For every 
generated CAST, `SqlOperator.deriveType` constructs temporary operand/type 
lists and performs routine lookup.
   
   With this change, the existing built-in operator validates the generated 
CAST immediately:
   
   ```text
   Create built-in CAST node
     -> cast.getOperator().validateOperands(...)
     -> infer and register the CAST type immediately
     -> later validator.deriveType(cast)
     -> validated-type cache hit; return immediately
   ```
   
   This keeps the same operand validation and return-type inference while 
removing the redundant operator-resolution path.
   
   ## Benchmark
   
   Measured with Druid's `InPlanningBenchmark.queryStringInSqlPlanOnly`, 
comparing Calcite 1.42 plus CALCITE-7782 against the same baseline with only 
this change. Configuration: 2 warmup iterations, 5 measurement iterations, 2 
forks, 1 second per iteration. Allocation is total allocated bytes per planning 
operation, not retained or peak heap.
   
   | String literals | Baseline allocation | This change | Reduction |
   | ---: | ---: | ---: | ---: |
   | 100,000 | 1,448.09 MiB/op | 1,159.19 MiB/op | 288.90 MiB/op (19.95%) |
   | 1,000,000 | 14,653.13 MiB/op | 11,651.62 MiB/op | 3,001.52 MiB/op (20.48%) 
|
   
   Average planning time changed from 749.87 to 735.42 ms/op at 100,000 
literals and from 7,978.14 to 7,585.11 ms/op at 1,000,000. The timing 
confidence intervals overlap, so these runs establish the allocation 
improvement but do not claim a statistically reliable latency improvement.
   
   ## Validation
   
   - `./gradlew :core:test --tests org.apache.calcite.test.SqlValidatorTest 
:core:autostyleJavaCheck :core:checkstyleTest` (596 completed, 0 failed, 7 
skipped)
   - Isolated Druid JMH benchmark at 100,000 and 1,000,000 string literals
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to