| 2202 | } |
| 2203 | |
| 2204 | Strings MergeTreeMetaBase::selectPartitionsByPredicate( |
| 2205 | const SelectQueryInfo & query_info, |
| 2206 | std::vector<std::shared_ptr<MergeTreePartition>> & partition_list, |
| 2207 | const Names & column_names_to_return, |
| 2208 | ContextPtr local_context, |
| 2209 | const bool & ignore_ttl) const |
| 2210 | { |
| 2211 | /// Coarse grained partition pruner: filter out the partition which will definitely not satisfy the query predicate. The benefit |
| 2212 | /// is 2-folded: (1) we can prune data parts and (2) we can reduce numbers of calls to catalog to get parts 's metadata. |
| 2213 | /// Note that this step still leaves false-positive parts. For example, the partition key is `toMonth(date)` and the query |
| 2214 | /// condition is `date > '2022-02-22' and date < '2022-03-22'` then this step won't eliminate any partition. |
| 2215 | |
| 2216 | /// The partition pruning rules come from 3 types: |
| 2217 | /// (1) TTL |
| 2218 | /// (2) Columns in predicate that exactly match the partition key |
| 2219 | /// (3) `_partition_id` or `_partition_value` if they're in predicate |
| 2220 | |
| 2221 | /// (1) Prune partition by partition level TTL |
| 2222 | if (!ignore_ttl) |
| 2223 | filterPartitionByTTL(partition_list, local_context->tryGetCurrentTransactionID().toSecond()); |
| 2224 | |
| 2225 | const auto partition_key = MergeTreePartition::adjustPartitionKey(getInMemoryMetadataPtr(), local_context); |
| 2226 | const auto & partition_key_expr = partition_key.expression; |
| 2227 | const auto & partition_key_sample = partition_key.sample_block; |
| 2228 | if (partition_key_sample.columns() > 0) |
| 2229 | { |
| 2230 | /// (2) Prune partitions if there's a column in predicate that exactly match the partition key |
| 2231 | Names partition_key_columns; |
| 2232 | for (const auto & name : partition_key_sample) |
| 2233 | { |
| 2234 | partition_key_columns.emplace_back(name.name); |
| 2235 | } |
| 2236 | |
| 2237 | KeyCondition partition_condition(query_info, local_context, partition_key_columns, partition_key_expr); |
| 2238 | DataTypes result; |
| 2239 | result.reserve(partition_key_sample.getDataTypes().size()); |
| 2240 | for (const auto & data_type : partition_key_sample.getDataTypes()) |
| 2241 | { |
| 2242 | result.push_back(DataTypeFactory::instance().get(data_type->getName(), data_type->getFlags())); |
| 2243 | } |
| 2244 | size_t prev_sz = partition_list.size(); |
| 2245 | std::erase_if(partition_list, [&](const auto & partition) { |
| 2246 | const auto & partition_value = partition->value; |
| 2247 | std::vector<FieldRef> index_value(partition_value.begin(), partition_value.end()); |
| 2248 | auto res = partition_condition.mayBeTrueInRange(partition_key_columns.size(), index_value.data(), index_value.data(), result); |
| 2249 | LOG_TRACE( |
| 2250 | log, |
| 2251 | "Key condition {} is {} in [ ({}) - ({}) )", |
| 2252 | partition_condition.toString(), |
| 2253 | res, |
| 2254 | fmt::join(index_value, " "), |
| 2255 | fmt::join(index_value, " ")); |
| 2256 | return !res; |
| 2257 | }); |
| 2258 | if (partition_list.size() < prev_sz) |
| 2259 | LOG_DEBUG(log, "Query predicates on physical columns dropped {} partitions", prev_sz - partition_list.size()); |
| 2260 | |
| 2261 | /// (3) Prune partitions if there's `_partition_id` or `_partition_value` in query predicate |
no test coverage detected