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

   ## Jira Link
   
   [CALCITE-7805](https://issues.apache.org/jira/browse/CALCITE-7805)
   
   ## Changes Proposed
   
   Large string ARRAY validation repeatedly combines compatible character types.
   The least-restrictive path may call `createTypeWithCharsetAndCollation` even 
when
   the current `BasicSqlType` already has the requested charset and collation.
   
   Previously, `BasicSqlType.createWithCharsetAndCollation` always allocated a 
new
   `BasicSqlType` and `SerializableCharset`; type-factory canonicalization then
   reduced that new object back to the existing canonical type. Return the 
existing
   immutable `BasicSqlType` immediately when the requested charset is equal and 
the
   collation is the same instance. Requests that change either attribute keep 
the
   existing construction and canonicalization path.
   
   This is an unchanged-attribute fast path, not a cache. It does not depend on 
a
   previous invocation or retain derived types.
   
   This branch is based directly on `main` at `38413ece6` and is independent of
   the other allocation optimizations.
   
   ## Execution Path
   
   There are two relevant charset/collation operations in the benchmark, and 
this
   change applies only to the second one.
   
   ### 1. Creating a string literal: attributes change
   
   A SQL string literal starts from a character type with the default charset 
and
   `IMPLICIT` collation. `SqlLiteral.createSqlType` then assigns the literal's
   `COERCIBLE` collation:
   
   ```text
   CHAR(n), default charset, IMPLICIT
     -> createTypeWithCharsetAndCollation(default charset, COERCIBLE)
     -> attributes differ, so a derived type is required
   ```
   
   The new condition is false on this path. This PR does not avoid that 
allocation.
   
   ### 2. Combining the column and literal: attributes are unchanged
   
   During least-restrictive inference, Calcite combines the string column's
   `IMPLICIT` collation with the literal's `COERCIBLE` collation. The SQL 
collation
   rules select `IMPLICIT`. The newly created common result type already has the
   default charset and `IMPLICIT` collation, but `leastRestrictiveSqlType` 
applies
   those same attributes again:
   
   ```text
   column:  VARCHAR(...), IMPLICIT
   literal: CHAR(n),       COERCIBLE
     -> common collation: IMPLICIT
     -> create common result type, already default charset + IMPLICIT
     -> createTypeWithCharsetAndCollation(default charset, IMPLICIT)
   ```
   
   Before this change, the final call allocated an equivalent `BasicSqlType` and
   charset wrapper and then canonicalized it back to the original instance:
   
   ```text
   already-correct BasicSqlType
     -> allocate equivalent BasicSqlType
     -> allocate/wrap its charset
     -> canonize(newType)
     -> return the existing canonical type
   ```
   
   With this change:
   
   ```text
   already-correct BasicSqlType
     -> detect the same charset and collation
     -> return this
     -> canonize(existingType)
   ```
   
   This repeated least-restrictive operation is where the benchmark's allocation
   reduction comes from.
   
   ## Isolated Benchmark
   
   Druid's `InPlanningBenchmark.queryStringInSqlPlanOnly` was run against a 
Calcite
   1.42.0 + CALCITE-7782 baseline and the same baseline with only this PR's
   effective `BasicSqlType` change applied. The removed no-op 
`SqlTypeFactoryImpl`
   refactoring was excluded.
   
   | String literals | Allocation before | Allocation after | Allocation saved 
| Change | Time before | Time after |
   |---:|---:|---:|---:|---:|---:|---:|
   | 100,000 | 1,450.76 MiB/op | 1,319.51 MiB/op | 131.24 MiB/op | -9.05% | 
739.72 ms/op | 763.63 ms/op |
   | 1,000,000 | 14,703.47 MiB/op | 13,421.72 MiB/op | 1,281.76 MiB/op | -8.72% 
| 8.086 s/op | 8.142 s/op |
   
   The timing confidence intervals overlap, so these results establish the
   allocation reduction but do not establish a latency improvement or 
regression.
   Allocation is total allocated bytes per planning operation, not retained or 
peak
   heap.
   
   The benchmark generates ordered numeric strings (`'1'`, `'2'`, ...). The
   optimization itself is based on unchanged charset and collation rather than
   literal-value order, but the measurements describe this specific workload and
   should not be generalized to all string expressions.
   
   Benchmark parameters: `inSubQueryThreshold=2147483647`,
   `rowsPerSegment=500000`; 2 JMH forks, each with 2 one-second warmup 
iterations
   and 5 one-second measured iterations; GC profiler; Temurin 25.0.4.1.
   
   ## Validation
   
   - `./gradlew :core:test --tests 
org.apache.calcite.sql.type.SqlTypeFactoryTest :core:autostyleJavaCheck 
:core:checkstyleMain :core:checkstyleTest` (27 completed, 0 failed)
   - 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