Skip to content

TTL GROUP BY passes min_chunk_bytes_for_parallel_parsing as min_hit_rate_to_use_consecutive_keys_optimization #112075

Closed

Description

@harikrishnan94

/*only_merge=*/false,
settings[Setting::optimize_group_by_constant_keys],
static_cast<float>(settings[Setting::min_chunk_bytes_for_parallel_parsing]),
/*stats_collecting_params_=*/{},

        /*only_merge=*/false,
        settings[Setting::optimize_group_by_constant_keys],
        static_cast<float>(settings[Setting::min_chunk_bytes_for_parallel_parsing]),
        /*stats_collecting_params_=*/{},

That argument of Aggregator::Params is min_hit_rate_to_use_consecutive_keys_optimization_, a hit rate in [0, 1], default 0.5. min_chunk_bytes_for_parallel_parsing is a byte threshold, default 10 MiB. So the threshold becomes 10485760.0, cache_hit_rate in Aggregator::executeImpl is at most 1.0, and the consecutive keys optimization is always disabled in TTL GROUP BY aggregation. Since 23.12. Perf only, results are not affected. There is no parallel parsing anywhere in this file, the extern for min_chunk_bytes_for_parallel_parsing exists only to feed this argument.

Copy-paste error from #57872, which introduced the parameter and updated every other Aggregator::Params call site with the correct setting. #94643 later wrapped it in static_cast<float> and silenced the exact UInt64 to float conversion warning that would have caught it. I checked all Aggregator::Params construction sites in src/ (both ctors), this is the only wrong one.

Fix: declare extern const SettingsFloat min_hit_rate_to_use_consecutive_keys_optimization in the Setting namespace of the file, pass it instead, and drop the now unused min_chunk_bytes_for_parallel_parsing extern.

Caused by: #57872
Related: #94643

Activity

  1. harikrishnan94 commented on Jul 27, 2026

    @harikrishnan94
    ContributorAuthor
  2. groeneai commented on Jul 27, 2026

    @groeneai
    Collaborator

    Acknowledged -- I reproduced the analysis on origin/master and it holds. I'll follow up here with a PR.

    Re-derived, so the record is complete:

    • Argument position confirmed. Aggregator::Params' full ctor (src/Interpreters/Aggregator.h:152-174) takes float min_hit_rate_to_use_consecutive_keys_optimization_ right after optimize_group_by_constant_keys_, and TTLAggregationAlgorithm::TTLAggregationAlgorithm passes min_chunk_bytes_for_parallel_parsing there. min_chunk_bytes_for_parallel_parsing is NonZeroUInt64 default 10 * 1024 * 1024 (Settings.cpp:1550); min_hit_rate_to_use_consecutive_keys_optimization is Float default 0.5 (Settings.cpp:6079). In Aggregator::executeImpl the comparison is cache_hit_rate >= params.min_hit_rate_to_use_consecutive_keys_optimization with cache_hit_rate at most 1.0, so use_cache is unconditionally false on this path.

    • Your completeness claim checks out. I swept every Aggregator::Params construction site in src/ against both ctors: InterpreterSelectQuery.cpp:2401 and :2990, Planner.cpp:653 and :785, AggregatingStep.cpp:1113, MergingAggregatedStep.cpp:311, LazyReadReplacingFinalSource.cpp:240, MergingAggregatedTransform.cpp:88 (forwards params.min_hit_rate_...), plus the gtest at gtest_aggregating_step_clears_reduced_flag.cpp:47 (0.5f). All correct. TTLAggregationAlgorithm.cpp is the only wrong one, and its min_chunk_bytes_for_parallel_parsing extern has exactly the two occurrences you describe -- the declaration and this argument.

    • Blame confirmed: 10bc2db56d2425 (Better optimization of consecutive keys in aggregation #57872) added the argument and set the correct setting at every other site it touched in the same commit; dc3d47d6899a0b (Enable implicit-int-float-conversion check #94643) added the static_cast<float>. First release containing it is v23.12.1.1368-stable.

    One thing worth adding: disabling the cache costs more than the last-element lookup. use_cache == false selects Method::StateNoCache, whose hasOnlyOneValueSinceLastReset() returns false unconditionally (ColumnsHashingImpl.h:341-346), and Aggregator::executeAggregateInstructions gates the equal-key-range batching on exactly that value -- so addBatchSinglePlace over a whole run of equal keys is never taken either, and the AggregationOptimizedEqualRangesOfKeys profile event stays at zero for TTL GROUP BY. That makes the TTL path the worst place to lose it: TTLAggregationAlgorithm::execute walks the block detecting group-key changes and calls calculateAggregates once per run of equal keys, i.e. every executeOnBlock call is a single-key run -- the exact shape the optimization exists for.

    I'll keep the PR to the one concern: declare extern const SettingsFloat min_hit_rate_to_use_consecutive_keys_optimization, pass it, drop the now unused min_chunk_bytes_for_parallel_parsing extern. Changelog category Performance Improvement, since results are unaffected as you note.

  3. groeneai commented on Jul 28, 2026

    @groeneai
    Collaborator

    PR: #112314

    It is the two-line change you described: the argument now passes min_hit_rate_to_use_consecutive_keys_optimization, and the min_chunk_bytes_for_parallel_parsing extern (which existed only to feed that slot) is removed.

    Two things worth flagging beyond the fix itself:

    • A stateless test (04648_ttl_group_by_consecutive_keys_optimization) asserts ProfileEvents['AggregationOptimizedEqualRangesOfKeys'] > 0 on the MergeParts row in system.part_log after a TTL ... GROUP BY merge. That event reads 0 before the fix and non-zero after, and reverting only the argument reproduces the failure as a one-line reference diff while count()/sum(v) stay byte-identical, which is the "perf only, results are not affected" half of your report measured rather than asserted.
    • I quote no local wall-clock figure. Only a debug build was available to me, so the release number comes from the PR's own Performance Comparison jobs, for which the PR adds tests/performance/ttl_group_by_consecutive_keys.xml timing the aggregating TTL merge.

    One note on reachability that may matter for anyone hitting this in production: the call site reads the global context (MergeTreeData holds context_->getGlobalContext()), so this setting cannot be influenced by OPTIMIZE ... SETTINGS, a session SET, or a client option. Only the server's default profile reaches it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions