| 963 | |
| 964 | |
| 965 | Pipe ReadFromMergeTree::spreadMarkRangesAmongStreamsFinal( |
| 966 | RangesInDataParts && parts_with_ranges, |
| 967 | const Names & column_names, |
| 968 | ActionsDAGPtr & out_projection) |
| 969 | { |
| 970 | const auto & settings = context->getSettingsRef(); |
| 971 | const auto data_settings = data.getSettings(); |
| 972 | |
| 973 | PartRangesReadInfo info(parts_with_ranges, settings, *data_settings); |
| 974 | |
| 975 | size_t num_streams = requested_num_streams; |
| 976 | if (num_streams > settings.max_final_threads) |
| 977 | num_streams = settings.max_final_threads; |
| 978 | |
| 979 | /// If setting do_not_merge_across_partitions_select_final is true than we won't merge parts from different partitions. |
| 980 | /// We have all parts in parts vector, where parts with same partition are nearby. |
| 981 | /// So we will store iterators pointed to the beginning of each partition range (and parts.end()), |
| 982 | /// then we will create a pipe for each partition that will run selecting processor and merging processor |
| 983 | /// for the parts with this partition. In the end we will unite all the pipes. |
| 984 | std::vector<RangesInDataParts::iterator> parts_to_merge_ranges; |
| 985 | auto it = parts_with_ranges.begin(); |
| 986 | parts_to_merge_ranges.push_back(it); |
| 987 | |
| 988 | if (settings.do_not_merge_across_partitions_select_final) |
| 989 | { |
| 990 | while (it != parts_with_ranges.end()) |
| 991 | { |
| 992 | it = std::find_if( |
| 993 | it, parts_with_ranges.end(), [&it](auto & part) { return it->data_part->info.partition_id != part.data_part->info.partition_id; }); |
| 994 | parts_to_merge_ranges.push_back(it); |
| 995 | } |
| 996 | /// We divide threads for each partition equally. But we will create at least the number of partitions threads. |
| 997 | /// (So, the total number of threads could be more than initial num_streams. |
| 998 | num_streams /= (parts_to_merge_ranges.size() - 1); |
| 999 | } |
| 1000 | else |
| 1001 | { |
| 1002 | /// If do_not_merge_across_partitions_select_final is false we just merge all the parts. |
| 1003 | parts_to_merge_ranges.push_back(parts_with_ranges.end()); |
| 1004 | } |
| 1005 | |
| 1006 | Pipes partition_pipes; |
| 1007 | |
| 1008 | /// If do_not_merge_across_partitions_select_final is true and num_streams > 1 |
| 1009 | /// we will store lonely parts with level > 0 to use parallel select on them. |
| 1010 | std::vector<RangesInDataPart> lonely_parts; |
| 1011 | size_t sum_marks_in_lonely_parts = 0; |
| 1012 | |
| 1013 | for (size_t range_index = 0; range_index < parts_to_merge_ranges.size() - 1; ++range_index) |
| 1014 | { |
| 1015 | Pipe pipe; |
| 1016 | |
| 1017 | { |
| 1018 | RangesInDataParts new_parts; |
| 1019 | |
| 1020 | /// If do_not_merge_across_partitions_select_final is true and there is only one part in partition |
| 1021 | /// with level > 0 then we won't postprocess this part and if num_streams > 1 we |
| 1022 | /// can use parallel select on such parts. We save such parts in one vector and then use |
nothing calls this directly
no test coverage detected