@@ -2074,9 +2074,8 @@ bool CheckSupportedQuery(THD *thd, JOIN *join) {
2074
2074
that are not aggregate functions. This is a tiny performance loss,
2075
2075
but makes things simpler.
2076
2076
2077
- Note that we cannot set up an access path for this temporary table yet;
2078
- that needs to wait until we know whether the sort decided to use row IDs
2079
- or not, and Filesort cannot be set up until it knows what tables to sort.
2077
+ Note that we don't set up an access path for this temporary table yet,
2078
+ since there may be multiple access paths sharing this temporary table.
2080
2079
Thus, that job is deferred to CreateMaterializationPathForSortingAggregates().
2081
2080
*/
2082
2081
TABLE *CreateTemporaryTableForSortingAggregates (
@@ -2243,8 +2242,9 @@ void ReplaceOrderItemsWithTempTableFields(THD *thd, ORDER *order) {
2243
2242
*/
2244
2243
AccessPath *CreateMaterializationPathForSortingAggregates (
2245
2244
THD *thd, JOIN *join, AccessPath *path, TABLE *temp_table,
2246
- Temp_table_param *temp_table_param, bool using_addon_fields) {
2247
- if (using_addon_fields) {
2245
+ Temp_table_param *temp_table_param) {
2246
+ // See if later sorts will need row IDs from us or not.
2247
+ if (!SortWillBeOnRowId (temp_table)) {
2248
2248
// The common case; we can use streaming.
2249
2249
AccessPath *stream_path =
2250
2250
NewStreamingAccessPath (thd, path, join, temp_table_param, temp_table,
@@ -2443,12 +2443,10 @@ JoinHypergraph::Node *FindNodeWithTable(JoinHypergraph *graph, TABLE *table) {
2443
2443
Prealloced_array<AccessPath *, 4 > ApplyDistinctAndOrder (
2444
2444
THD *thd, const CostingReceiver &receiver,
2445
2445
const LogicalOrderings &orderings, bool aggregation_is_unordered,
2446
- int order_by_ordering_idx, int distinct_ordering_idx, ORDER *distinct_order,
2446
+ int order_by_ordering_idx, int distinct_ordering_idx,
2447
2447
const Mem_root_array<SortAheadOrdering> &sort_ahead_orderings,
2448
- FunctionalDependencySet fd_set , Query_block *query_block,
2449
- bool need_rowid_from_tables,
2450
- Prealloced_array<AccessPath *, 4 > root_candidates, string *trace,
2451
- TABLE **temp_table) {
2448
+ FunctionalDependencySet fd_set , Query_block *query_block, bool need_rowid,
2449
+ Prealloced_array<AccessPath *, 4 > root_candidates, string *trace) {
2452
2450
JOIN *join = query_block->join ;
2453
2451
assert (join->select_distinct || query_block->is_ordered ());
2454
2452
@@ -2458,11 +2456,7 @@ Prealloced_array<AccessPath *, 4> ApplyDistinctAndOrder(
2458
2456
return root_candidates;
2459
2457
}
2460
2458
2461
- *temp_table = nullptr ;
2462
- Temp_table_param *temp_table_param = nullptr ;
2463
-
2464
- Mem_root_array<TABLE *> tables =
2465
- CollectTables (thd, root_candidates[0 ]); // Should be same for all paths.
2459
+ bool inserted_temp_table = false ;
2466
2460
2467
2461
// If we have grouping followed by a sort, we need to bounce via
2468
2462
// the buffers of a temporary table. See the comments on
@@ -2475,93 +2469,23 @@ Prealloced_array<AccessPath *, 4> ApplyDistinctAndOrder(
2475
2469
// doesn't preserve them (doing so would probably not be worth it for
2476
2470
// something that's fairly niche).
2477
2471
//
2478
- // NOTE: We could need row IDs later without need_rowid_from_tables being set,
2479
- // but only in certain edge cases; for instance, if we sort only constants
2480
- // (although filesort should arguably be fixed not to request row IDs
2481
- // in that case). The test here is really about data being pulled from
2482
- // individual tables, and should be safe.
2483
- if (query_block->is_explicitly_grouped () &&
2484
- (*join->sum_funcs != nullptr ||
2485
- join->rollup_state != JOIN::RollupState::NONE ||
2486
- need_rowid_from_tables)) {
2487
- *temp_table = CreateTemporaryTableForSortingAggregates (thd, query_block,
2488
- &temp_table_param);
2489
- // Filesort now only needs to worry about one input -- this temporary
2490
- // table. This holds whether we are actually materializing or just
2491
- // using streaming.
2492
- tables.clear ();
2493
- tables.push_back (*temp_table);
2494
- }
2495
-
2496
- // Set up the filesort objects. They have some interactions
2497
- // around addon fields vs. sort by row ID, so we need to do this
2498
- // before we decide on iterators.
2499
- bool need_rowid = false ;
2500
- Filesort *filesort = nullptr ;
2501
- if (query_block->is_ordered ()) {
2502
- Mem_root_array<TABLE *> table_copy (thd->mem_root , tables.begin (),
2503
- tables.end ());
2504
- filesort = new (thd->mem_root )
2505
- Filesort (thd, std::move (table_copy), /* keep_buffers=*/ false ,
2506
- query_block->order_list .first ,
2507
- /* limit_arg=*/ HA_POS_ERROR, /* force_stable_sort=*/ false ,
2508
- /* remove_duplicates=*/ false , /* force_sort_positions=*/ false ,
2509
- /* unwrap_rollup=*/ false );
2510
- join->filesorts_to_cleanup .push_back (filesort);
2511
- need_rowid = !filesort->using_addon_fields ();
2512
- }
2513
- Filesort *filesort_for_distinct = nullptr ;
2514
- if (join->select_distinct ) {
2515
- bool force_sort_positions = false ;
2516
- if (filesort != nullptr && !filesort->using_addon_fields ()) {
2517
- // We have the rather unusual situation here that we have two sorts
2518
- // directly after each other, with no temporary table in-between,
2519
- // and filesort expects to be able to refer to rows by their position.
2520
- // Usually, the sort for DISTINCT would be a superset of the sort for
2521
- // ORDER BY, but not always (e.g. when sorting by some expression),
2522
- // so we could end up in a situation where the first sort is by addon
2523
- // fields and the second one is by positions.
2524
- //
2525
- // Thus, in this case, we force the first sort to be by positions,
2526
- // so that the result comes from SortFileIndirectIterator or
2527
- // SortBufferIndirectIterator. These will both position the cursor
2528
- // on the underlying temporary table correctly before returning it,
2529
- // so that the successive filesort will save the right position
2530
- // for the row.
2531
- if (trace != nullptr ) {
2532
- *trace +=
2533
- " Forcing DISTINCT to sort row IDs, since ORDER BY sort does\n " ;
2534
- }
2535
- force_sort_positions = true ;
2536
- }
2537
-
2538
- if (distinct_order != nullptr ) {
2539
- filesort_for_distinct = new (thd->mem_root )
2540
- Filesort (thd, std::move (tables),
2541
- /* keep_buffers=*/ false , distinct_order, HA_POS_ERROR,
2542
- /* force_stable_sort=*/ false ,
2543
- /* remove_duplicates=*/ true , force_sort_positions,
2544
- /* unwrap_rollup=*/ false );
2545
- join->filesorts_to_cleanup .push_back (filesort_for_distinct);
2546
- if (!filesort_for_distinct->using_addon_fields ()) {
2547
- need_rowid = true ;
2548
- }
2549
- }
2550
- }
2551
-
2552
- // Apply streaming between grouping and us, if needed (see above).
2553
2472
// NOTE: If we elide the sort due to interesting orderings, this might
2554
2473
// be redundant. It is fairly harmless, though.
2555
- if (*temp_table != nullptr ) {
2474
+ if (query_block->is_explicitly_grouped () &&
2475
+ (*join->sum_funcs != nullptr ||
2476
+ join->rollup_state != JOIN::RollupState::NONE || need_rowid)) {
2477
+ Temp_table_param *temp_table_param = nullptr ;
2478
+ TABLE *temp_table = CreateTemporaryTableForSortingAggregates (
2479
+ thd, query_block, &temp_table_param);
2556
2480
Prealloced_array<AccessPath *, 4 > new_root_candidates (PSI_NOT_INSTRUMENTED);
2557
2481
for (AccessPath *root_path : root_candidates) {
2558
2482
root_path = CreateMaterializationPathForSortingAggregates (
2559
- thd, join, root_path, *temp_table, temp_table_param,
2560
- /* using_addon_fields=*/ !need_rowid);
2483
+ thd, join, root_path, temp_table, temp_table_param);
2561
2484
receiver.ProposeAccessPath (root_path, &new_root_candidates,
2562
2485
/* obsolete_orderings=*/ 0 , " " );
2563
2486
}
2564
2487
root_candidates = std::move (new_root_candidates);
2488
+ inserted_temp_table = true ;
2565
2489
}
2566
2490
2567
2491
// Now create iterators for DISTINCT, if applicable.
@@ -2610,40 +2534,38 @@ Prealloced_array<AccessPath *, 4> ApplyDistinctAndOrder(
2610
2534
if (!orderings.DoesFollowOrder (ordering_state, distinct_ordering_idx)) {
2611
2535
continue ;
2612
2536
}
2613
- AccessPath *sort_path =
2614
- NewSortAccessPath (thd, root_path, filesort_for_distinct,
2615
- /* count_examined_rows=*/ false );
2616
- EstimateSortCost (sort_path);
2537
+ AccessPath sort_path;
2538
+ sort_path.type = AccessPath::SORT;
2539
+ sort_path.count_examined_rows = false ;
2540
+ sort_path.sort ().child = root_path;
2541
+ sort_path.sort ().filesort = nullptr ;
2542
+ sort_path.sort ().remove_duplicates = true ;
2543
+ sort_path.sort ().unwrap_rollup = false ;
2544
+
2617
2545
if (aggregation_is_unordered) {
2618
2546
// Even though we create a sort node for the distinct operation,
2619
2547
// the engine does not actually sort the rows. (The deduplication
2620
2548
// flag is the hint in this case.)
2621
- sort_path-> ordering_state = 0 ;
2549
+ sort_path. ordering_state = 0 ;
2622
2550
} else {
2623
- sort_path-> ordering_state = ordering_state;
2551
+ sort_path. ordering_state = ordering_state;
2624
2552
}
2625
2553
2626
- // Swap out the ordering for the order we're actually using.
2627
- // filesort_for_distinct was only used for setting row ID status,
2628
- // and we can keep that information, but we need to use the right
2629
- // ordering.
2630
- sort_path->sort ().filesort = nullptr ;
2631
- sort_path->sort ().remove_duplicates = true ;
2632
- sort_path->sort ().unwrap_rollup = false ;
2633
- if (*temp_table != nullptr ) {
2554
+ if (inserted_temp_table) {
2634
2555
ORDER *order_copy = BuildSortAheadOrdering (
2635
2556
thd, &orderings,
2636
2557
orderings.ordering (sort_ahead_ordering.ordering_idx ));
2637
2558
ReplaceOrderItemsWithTempTableFields (thd, order_copy);
2638
- sort_path-> sort ().order = order_copy;
2559
+ sort_path. sort ().order = order_copy;
2639
2560
} else {
2640
- sort_path-> sort ().order = sort_ahead_ordering.order ;
2561
+ sort_path. sort ().order = sort_ahead_ordering.order ;
2641
2562
}
2642
2563
2643
- if (!filesort_for_distinct-> using_addon_fields () ) {
2644
- FindTablesToGetRowidFor (sort_path);
2564
+ if (need_rowid ) {
2565
+ FindTablesToGetRowidFor (& sort_path);
2645
2566
}
2646
- receiver.ProposeAccessPath (sort_path, &new_root_candidates,
2567
+ EstimateSortCost (&sort_path);
2568
+ receiver.ProposeAccessPath (&sort_path, &new_root_candidates,
2647
2569
/* obsolete_orderings=*/ 0 , " " );
2648
2570
}
2649
2571
}
@@ -2652,6 +2574,15 @@ Prealloced_array<AccessPath *, 4> ApplyDistinctAndOrder(
2652
2574
2653
2575
// Apply ORDER BY, if applicable.
2654
2576
if (query_block->is_ordered ()) {
2577
+ Mem_root_array<TABLE *> tables = CollectTables (
2578
+ thd, root_candidates[0 ]); // Should be same for all paths.
2579
+ Filesort *filesort = new (thd->mem_root )
2580
+ Filesort (thd, std::move (tables), /* keep_buffers=*/ false ,
2581
+ query_block->order_list .first ,
2582
+ /* limit_arg=*/ HA_POS_ERROR, /* force_stable_sort=*/ false ,
2583
+ /* remove_duplicates=*/ false , /* force_sort_positions=*/ false ,
2584
+ /* unwrap_rollup=*/ false );
2585
+ join->filesorts_to_cleanup .push_back (filesort);
2655
2586
if (trace != nullptr ) {
2656
2587
*trace += " Applying sort for ORDER BY\n " ;
2657
2588
}
@@ -3044,8 +2975,8 @@ static void BuildInterestingOrders(
3044
2975
LogicalOrderings *orderings,
3045
2976
Mem_root_array<SortAheadOrdering> *sort_ahead_orderings,
3046
2977
int *order_by_ordering_idx, int *group_by_ordering_idx,
3047
- int *distinct_ordering_idx, ORDER **distinct_order ,
3048
- Mem_root_array<ActiveIndexInfo> *active_indexes, string *trace) {
2978
+ int *distinct_ordering_idx, Mem_root_array<ActiveIndexInfo> *active_indexes ,
2979
+ string *trace) {
3049
2980
// Collect ordering from ORDER BY.
3050
2981
if (query_block->is_ordered ()) {
3051
2982
table_map used_tables;
@@ -3103,7 +3034,6 @@ static void BuildInterestingOrders(
3103
3034
/* order_for_filesort=*/ order,
3104
3035
/* used_at_end=*/ true , /* homogenize_tables=*/ 0 , used_tables,
3105
3036
orderings, sort_ahead_orderings);
3106
- *distinct_order = order;
3107
3037
}
3108
3038
3109
3039
// Collect groupings from semijoins (because we might want to do duplicate
@@ -3415,11 +3345,10 @@ AccessPath *FindBestQueryPlan(THD *thd, Query_block *query_block,
3415
3345
int order_by_ordering_idx = -1 ;
3416
3346
int group_by_ordering_idx = -1 ;
3417
3347
int distinct_ordering_idx = -1 ;
3418
- ORDER *distinct_order = nullptr ;
3419
3348
BuildInterestingOrders (thd, &graph, query_block, &orderings,
3420
3349
&sort_ahead_orderings, &order_by_ordering_idx,
3421
3350
&group_by_ordering_idx, &distinct_ordering_idx,
3422
- &distinct_order, & active_indexes, trace);
3351
+ &active_indexes, trace);
3423
3352
3424
3353
// Run the actual join optimizer algorithm. This creates an access path
3425
3354
// for the join as a whole (with lowest possible cost, and thus also
@@ -3675,13 +3604,11 @@ AccessPath *FindBestQueryPlan(THD *thd, Query_block *query_block,
3675
3604
root_candidates = std::move (new_root_candidates);
3676
3605
}
3677
3606
3678
- TABLE *temp_table = nullptr ;
3679
3607
if (join->select_distinct || query_block->is_ordered ()) {
3680
3608
root_candidates = ApplyDistinctAndOrder (
3681
3609
thd, receiver, orderings, aggregation_is_unordered,
3682
- order_by_ordering_idx, distinct_ordering_idx, distinct_order,
3683
- sort_ahead_orderings, fd_set , query_block, need_rowid,
3684
- std::move (root_candidates), trace, &temp_table);
3610
+ order_by_ordering_idx, distinct_ordering_idx, sort_ahead_orderings,
3611
+ fd_set , query_block, need_rowid, std::move (root_candidates), trace);
3685
3612
}
3686
3613
3687
3614
// Apply LIMIT, if applicable.
0 commit comments