| 153 | } |
| 154 | |
| 155 | void LazyFinalKeyAnalysisTransform::work() |
| 156 | { |
| 157 | auto reading = buildReadingStep( |
| 158 | metadata_snapshot, mutations_snapshot, storage_snapshot, |
| 159 | data_settings, data, max_block_numbers_to_read, ranges, query_context); |
| 160 | |
| 161 | /// Count total marks before index analysis. |
| 162 | size_t total_marks = 0; |
| 163 | for (const auto & part : reading->getParts()) |
| 164 | total_marks += part.getMarksCount(); |
| 165 | |
| 166 | /// Build and apply the IN-set filter for index analysis. |
| 167 | { |
| 168 | const auto & primary_key = metadata_snapshot->getPrimaryKey(); |
| 169 | |
| 170 | ActionsDAG filter_dag = primary_key.expression->getActionsDAG().clone(); |
| 171 | filter_dag.getOutputs() = filter_dag.findInOutputs(primary_key.column_names); |
| 172 | |
| 173 | auto set_type = std::make_shared<DataTypeSet>(); |
| 174 | ColumnConst::Ptr set_column = ColumnConst::create(ColumnSet::create(1, future_set), 0); |
| 175 | |
| 176 | const auto * key_node = filter_dag.getOutputs().at(0); |
| 177 | if (filter_dag.getOutputs().size() > 1) |
| 178 | { |
| 179 | auto function_tuple = FunctionFactory::instance().get("tuple", query_context); |
| 180 | key_node = &filter_dag.addFunction(function_tuple, filter_dag.getOutputs(), {}); |
| 181 | } |
| 182 | const auto * set_node = &filter_dag.addColumn(std::move(set_column), std::move(set_type), ""); |
| 183 | auto function_in = FunctionFactory::instance().get("in", query_context); |
| 184 | const auto * in_func = &filter_dag.addFunction(function_in, {key_node, set_node}, {}); |
| 185 | filter_dag.getOutputs().push_back(in_func); |
| 186 | |
| 187 | reading->addFilter(std::move(filter_dag), in_func->result_name); |
| 188 | reading->SourceStepWithFilterBase::applyFilters(); |
| 189 | } |
| 190 | |
| 191 | /// Count marks after index analysis. |
| 192 | auto analysis_result = reading->selectRangesToRead(); |
| 193 | size_t selected_marks = 0; |
| 194 | if (analysis_result) |
| 195 | for (const auto & part : analysis_result->parts_with_ranges) |
| 196 | selected_marks += part.getMarksCount(); |
| 197 | |
| 198 | /// Check if enough marks were filtered by the IN-set. |
| 199 | float filtered_ratio = total_marks > 0 ? 1.0f - static_cast<float>(selected_marks) / static_cast<float>(total_marks) : 0.0f; |
| 200 | |
| 201 | if (min_filtered_ratio > 0 && filtered_ratio < min_filtered_ratio) |
| 202 | { |
| 203 | LOG_TRACE(log, |
| 204 | "Lazy FINAL disabled: filtered ratio {:.2f} is below threshold {:.2f} " |
| 205 | "(total_marks={}, selected_marks={}, set_rows={})", |
| 206 | filtered_ratio, min_filtered_ratio, |
| 207 | total_marks, selected_marks, future_set->get()->getTotalRowCount()); |
| 208 | should_signal = false; |
| 209 | } |
| 210 | else |
| 211 | { |
| 212 | LOG_TRACE(log, |
nothing calls this directly
no test coverage detected