Skip to content

Commit 974f5a7

Browse files
author
Chaithra Gopalareddy
committed
Bug#21178196 : UPDATE MAY USE INDEX MERGE WITHOUT ANY REASON
(INCREASING CHANCES FOR DEADLOCK) Problem: Index merge access plan is choosen over range scan when the cost for doing range scan would be same/less. Analysis: W.r.t the query presented in the bugpage, index merge access plan is choosen because it is covering. However, while calculating the cost for doing index merge scan, the current cost model thinks doing a sequential scan is more costly than doing a random scan. For the given case, while calculating the cost for disk sweep, we calculate cost for reading the blocks having the qualifying rows and the cost for skipping the other blocks. There is a minimal cost for skipping blocks too. And given that in this case, we are looking at one qualifying row and rejecting 1590000 rows, we would end up skipping a lot of blocks. As a result the total cost for doing sequential scan becomes larger than doing a random scan. This in turn makes optimizer think doing index merge is better than the other access plans. Solution: If it is calculated that sequential scan cost is more than random scan cost, set the cost to random scan cost. Also, set is_interrupted to true before calling get_sweep_read_cost when the plan is not single table. This will make both single table select and single table update choose the same code path. This is in line with other calls made to get_sweep_read_cost. Test case is not added as large amount of data is needed to get a repeatable scenario.
1 parent 01dab6b commit 974f5a7

3 files changed

Lines changed: 34 additions & 17 deletions

File tree

mysql-test/suite/opt_trace/r/range_no_prot.result

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3442,8 +3442,8 @@ EXPLAIN SELECT * FROM t1 WHERE cola = 'foo' AND colb = 'bar' {
34423442
"index": "cola",
34433443
"index_scan_cost": 11.231,
34443444
"cumulated_index_scan_cost": 11.231,
3445-
"disk_sweep_cost": 309.15,
3446-
"cumulated_total_cost": 320.38,
3445+
"disk_sweep_cost": 278.58,
3446+
"cumulated_total_cost": 289.81,
34473447
"usable": true,
34483448
"matching_rows_now": 533,
34493449
"isect_covering_with_this_index": false,
@@ -3453,8 +3453,8 @@ EXPLAIN SELECT * FROM t1 WHERE cola = 'foo' AND colb = 'bar' {
34533453
"index": "colb",
34543454
"index_scan_cost": 11.231,
34553455
"cumulated_index_scan_cost": 22.462,
3456-
"disk_sweep_cost": 30.898,
3457-
"cumulated_total_cost": 53.359,
3456+
"disk_sweep_cost": 28.152,
3457+
"cumulated_total_cost": 50.613,
34583458
"usable": true,
34593459
"matching_rows_now": 32.639,
34603460
"isect_covering_with_this_index": false,
@@ -3466,7 +3466,7 @@ EXPLAIN SELECT * FROM t1 WHERE cola = 'foo' AND colb = 'bar' {
34663466
"cause": "no_clustered_pk_index"
34673467
} /* clustered_pk */,
34683468
"rows": 32,
3469-
"cost": 53.359,
3469+
"cost": 50.613,
34703470
"covering": false,
34713471
"chosen": true
34723472
} /* analyzing_roworder_intersect */
@@ -3475,7 +3475,7 @@ EXPLAIN SELECT * FROM t1 WHERE cola = 'foo' AND colb = 'bar' {
34753475
"range_access_plan": {
34763476
"type": "index_roworder_intersect",
34773477
"rows": 32,
3478-
"cost": 53.359,
3478+
"cost": 50.613,
34793479
"covering": false,
34803480
"clustered_pk_scan": false,
34813481
"intersect_of": [
@@ -3498,7 +3498,7 @@ EXPLAIN SELECT * FROM t1 WHERE cola = 'foo' AND colb = 'bar' {
34983498
] /* intersect_of */
34993499
} /* range_access_plan */,
35003500
"rows_for_plan": 32,
3501-
"cost_for_plan": 53.359,
3501+
"cost_for_plan": 50.613,
35023502
"chosen": true
35033503
} /* chosen_range_access_summary */
35043504
} /* range_analysis */
@@ -3530,12 +3530,12 @@ EXPLAIN SELECT * FROM t1 WHERE cola = 'foo' AND colb = 'bar' {
35303530
{
35313531
"access_type": "range",
35323532
"rows": 24,
3533-
"cost": 59.759,
3533+
"cost": 57.013,
35343534
"chosen": true
35353535
}
35363536
] /* considered_access_paths */
35373537
} /* best_access_path */,
3538-
"cost_for_plan": 59.759,
3538+
"cost_for_plan": 57.013,
35393539
"rows_for_plan": 24,
35403540
"chosen": true
35413541
}
@@ -5519,8 +5519,8 @@ EXPLAIN SELECT v FROM t1 WHERE i1 = 1 AND i2 = 1 AND v = 'a' AND pk < 3 {
55195519
"index": "v_idx",
55205520
"index_scan_cost": 1,
55215521
"cumulated_index_scan_cost": 1,
5522-
"disk_sweep_cost": 1,
5523-
"cumulated_total_cost": 2,
5522+
"disk_sweep_cost": 0.9031,
5523+
"cumulated_total_cost": 1.9031,
55245524
"usable": true,
55255525
"matching_rows_now": 1,
55265526
"isect_covering_with_this_index": false,

sql/handler.cc

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6642,13 +6642,30 @@ void get_sweep_read_cost(TABLE *table, ha_rows nrows, bool interrupted,
66426642

66436643
DBUG_PRINT("info",("sweep: nblocks=%g, busy_blocks=%g", n_blocks,
66446644
busy_blocks));
6645-
if (interrupted)
6646-
cost->add_io(busy_blocks * Cost_estimate::IO_BLOCK_READ_COST());
6647-
else
6645+
/*
6646+
The random access cost for reading the data pages will be the
6647+
upper limit for the sweep_cost.
6648+
*/
6649+
cost->add_io(busy_blocks * Cost_estimate::IO_BLOCK_READ_COST());
6650+
6651+
if (!interrupted)
6652+
{
66486653
/* Assume reading is done in one 'sweep' */
6649-
cost->add_io(busy_blocks *
6654+
Cost_estimate sweep_cost;
6655+
sweep_cost.add_io(busy_blocks *
66506656
(DISK_SEEK_BASE_COST +
66516657
DISK_SEEK_PROP_COST * n_blocks / busy_blocks));
6658+
/*
6659+
For some cases, ex: when only few blocks need to be read
6660+
and the seek distance becomes very large, the sweep cost
6661+
model can produce a cost estimate that is larger than the
6662+
cost of random access. To handle this case, we use the
6663+
sweep cost only when it is less than the random access
6664+
cost.
6665+
*/
6666+
if (sweep_cost.get_io_cost() < cost->get_io_cost())
6667+
*cost= sweep_cost;
6668+
}
66526669
}
66536670
DBUG_PRINT("info",("returning cost=%g", cost->total_cost()));
66546671
DBUG_VOID_RETURN;

sql/opt_range.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights
1+
/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights
22
* reserved.
33
44
This program is free software; you can redistribute it and/or modify
@@ -5234,7 +5234,7 @@ static bool ror_intersect_add(ROR_INTERSECT_INFO *info,
52345234
{
52355235
Cost_estimate sweep_cost;
52365236
JOIN *join= info->param->thd->lex->select_lex.join;
5237-
const bool is_interrupted= join && join->tables == 1;
5237+
const bool is_interrupted= join && join->tables != 1;
52385238
get_sweep_read_cost(info->param->table, double2rows(info->out_rows),
52395239
is_interrupted, &sweep_cost);
52405240
info->total_cost += sweep_cost.total_cost();

0 commit comments

Comments
 (0)