gortiz opened a new issue, #19815:
URL: https://github.com/apache/pinot/issues/19815

   In the multi-stage engine, `FunctionOperand.apply` evaluates its operands 
and invokes the function for every input row. `TransformOperandFactory` creates 
a `FunctionOperand` for every function call, even when all its operands are 
literals, so a call like `f(1, 2)` runs again on each row.
   
   Most of the time this does not matter, because `PinotEvaluateLiteralRule` 
folds deterministic calls on literals at the broker, so they reach the workers 
as a `LiteralOperand`. But some calls are better left unfolded. In #19552 I'm 
marking `generateArray` as not foldable. Folding serializes the whole sequence, 
up to 100,000 elements, into the plan sent to every worker of the stage, while 
the workers only need the three arguments to generate it. The catch is that a 
call like this is now evaluated once per row whenever it runs in an 
intermediate stage:
   
   ```sql
   SELECT a.id, generateArray(0, 99999)
   FROM a JOIN b ON a.id = b.id
   ```
   
   The projection sits above the join, so it runs in the join's stage, and each 
joined row rebuilds a 100,000 element array that is the same every time. An 
uncorrelated `CROSS JOIN UNNEST(generateArray(...))` is not affected, because 
the planner puts the call in its own single-row Values stage. Leaf stages are 
fine: there the call goes through `GenerateArrayTransformFunction`, which 
`TransformFunctionFactory` shares per query context, so it is computed once per 
server.
   
   I suggest that `FunctionOperand` caches its result when every operand is a 
`LiteralOperand` and the function is `FunctionVolatility.IMMUTABLE`. Checking 
volatility instead of `FunctionInfo.isDeterministic()` matters here, because 
`generateArray` reports itself as non-deterministic only to opt out of folding. 
Computing the value lazily on the first `apply` keeps argument errors where 
they surface today, at execution time, and avoids computing results that are 
never used. The cached value is returned to every caller, so callers must not 
mutate it, which is the same contract `LiteralOperand` already has.
   
   This helps any function on literal arguments that is not folded, not only 
`generateArray`.
   


-- 
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]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to