Skip to content

Commit ffad6cf

Browse files
committed
Bug#35952353 SELECT COUNT(*) degraded performance on 8.0 compared to 5.7
Symptoms ---------- The SELECT COUNT(*) query that uses secondary index for scan, takes more than 6X with 8.0 compared to 5.7. Performance of the query that use the clustered index for scan is at par with 5.7. Background ---------- In 8.0.14, we introduced parallel scan of subtrees of a clustered index through 'WL#11720 InnoDB: Parallel read of index'. This feature was further improved through 'WL#12978 InnoDB:Fix imbalance during parallel scan' in 8.0.17. The idea of the second worklog was to utilize the parallel read threads which were introduced through first worklog. Second worklog also made another intentional change(not documented!) that is, secondary index scan in InnoDB started using the parallel scan of clustered index. In other words, even if Optimizer hints InnoDB to use secondary index for scan, InnoDB ignores that, and uses clustered index for scan. This observation was reported in the following bugs: 'Bug#31791868 INDEX HINT DOES NOT AFFECT COUNT(*) EXECUTION' 'Bug#35981123 SELECT COUNT is slow with O_DIRECT' The second worklog enabled the clustered index (parallel) scan even for secondary index scan for the following two reasons : - Post WL#12978, performance of clustered index scan was much improved. - Cost of scanning the secondary index is much higher to support the MVCC semantics i.e. read-committed, repeatable-read isolation levels. That is because before reporting a record from a secondary index, InnoDB must ensure it is visible to the query's read-view. That might require a dive into clustered index to consult corresponding row's undo chain. This can be avoided in case InnoDB sees that a secondary index record was not modified since read-view's creation, but unfortunately this information is not available per-row, only per-page. So, if any of the records on the page was modified since read-view's creation, the heuristic will not help, and dives to clustered index will be needed for all records from this secondary index page. The second reason is main argument behind this change which can be easily reproduced by modifying a few records in the table and then executing the query in a session that has read_view created before the modification, for example by having opened transaction on isolation level of Repeatable Read before the modifications. In my experiment, I found with secondary index scan(or with this fix), query performed 30X worse than the query performed without a read view. Thus it is really a trade off between using the clustered scan that is better in worst case vs using the secondary index as Optimizer hints which is better in most of the cases. Fix ---- - Do not break the contract with Optimizer(Bug#31791868). User now (again) has an option to provide index hint to the query, to force using clustered index. - We must improve Optimizer's heuristic so that it can hints the correct index to use. Created 'Bug#36297856 Query performance dropped by 30X with secondary index scan due to MVCC checks', for Optimizer team to improve the heuristic in Optimizer. - Reverted part of the WL#12978 changes that forced clustered index (parallel) scan for secondary index scan. Change-Id: Icb081d076cb6875e7b973e68ff6cfcce8ae3f82a
1 parent 43fc874 commit ffad6cf

File tree

3 files changed

+24
-34
lines changed

3 files changed

+24
-34
lines changed

mysql-test/r/select_count.result

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,10 @@ Handler_discover 0
5252
Handler_external_lock 2
5353
Handler_mrr_init 0
5454
Handler_prepare 0
55-
Handler_read_first 0
56-
Handler_read_key 0
55+
Handler_read_first 1
56+
Handler_read_key 1
5757
Handler_read_last 0
58-
Handler_read_next 0
58+
Handler_read_next 3
5959
Handler_read_prev 0
6060
Handler_read_rnd 0
6161
Handler_read_rnd_next 0
@@ -100,10 +100,10 @@ Handler_discover 0
100100
Handler_external_lock 4
101101
Handler_mrr_init 0
102102
Handler_prepare 0
103-
Handler_read_first 0
104-
Handler_read_key 0
103+
Handler_read_first 1
104+
Handler_read_key 1
105105
Handler_read_last 0
106-
Handler_read_next 0
106+
Handler_read_next 3
107107
Handler_read_prev 0
108108
Handler_read_rnd 0
109109
Handler_read_rnd_next 0
@@ -148,10 +148,10 @@ Handler_discover 0
148148
Handler_external_lock 2
149149
Handler_mrr_init 0
150150
Handler_prepare 0
151-
Handler_read_first 0
152-
Handler_read_key 1
151+
Handler_read_first 1
152+
Handler_read_key 2
153153
Handler_read_last 0
154-
Handler_read_next 0
154+
Handler_read_next 3
155155
Handler_read_prev 0
156156
Handler_read_rnd 0
157157
Handler_read_rnd_next 0
@@ -225,10 +225,10 @@ Handler_discover 0
225225
Handler_external_lock 2
226226
Handler_mrr_init 0
227227
Handler_prepare 0
228-
Handler_read_first 0
229-
Handler_read_key 0
228+
Handler_read_first 1
229+
Handler_read_key 1
230230
Handler_read_last 0
231-
Handler_read_next 0
231+
Handler_read_next 3
232232
Handler_read_prev 0
233233
Handler_read_rnd 0
234234
Handler_read_rnd_next 0
@@ -279,10 +279,10 @@ Handler_discover 0
279279
Handler_external_lock 2
280280
Handler_mrr_init 0
281281
Handler_prepare 0
282-
Handler_read_first 0
283-
Handler_read_key 0
282+
Handler_read_first 1
283+
Handler_read_key 1
284284
Handler_read_last 0
285-
Handler_read_next 0
285+
Handler_read_next 3
286286
Handler_read_prev 0
287287
Handler_read_rnd 0
288288
Handler_read_rnd_next 0
@@ -404,10 +404,10 @@ Handler_discover 0
404404
Handler_external_lock 4
405405
Handler_mrr_init 0
406406
Handler_prepare 0
407-
Handler_read_first 0
408-
Handler_read_key 0
407+
Handler_read_first 1
408+
Handler_read_key 1
409409
Handler_read_last 0
410-
Handler_read_next 0
410+
Handler_read_next 3
411411
Handler_read_prev 0
412412
Handler_read_rnd 0
413413
Handler_read_rnd_next 0
@@ -452,10 +452,10 @@ Handler_discover 0
452452
Handler_external_lock 4
453453
Handler_mrr_init 0
454454
Handler_prepare 0
455-
Handler_read_first 0
456-
Handler_read_key 0
455+
Handler_read_first 1
456+
Handler_read_key 1
457457
Handler_read_last 0
458-
Handler_read_next 0
458+
Handler_read_next 3
459459
Handler_read_prev 0
460460
Handler_read_rnd 0
461461
Handler_read_rnd_next 0
@@ -487,10 +487,10 @@ Handler_discover 0
487487
Handler_external_lock 2
488488
Handler_mrr_init 0
489489
Handler_prepare 0
490-
Handler_read_first 0
491-
Handler_read_key 0
490+
Handler_read_first 1
491+
Handler_read_key 1
492492
Handler_read_last 0
493-
Handler_read_next 0
493+
Handler_read_next 3
494494
Handler_read_prev 0
495495
Handler_read_rnd 0
496496
Handler_read_rnd_next 0

storage/innobase/handler/ha_innodb.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -253,11 +253,6 @@ class ha_innobase : public handler {
253253

254254
int records(ha_rows *num_rows) override;
255255

256-
int records_from_index(ha_rows *num_rows, uint) override {
257-
/* Force use of cluster index until we implement sec index parallel scan. */
258-
return ha_innobase::records(num_rows);
259-
}
260-
261256
ha_rows records_in_range(uint inx, key_range *min_key,
262257
key_range *max_key) override;
263258

storage/innobase/handler/ha_innopart.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,11 +1114,6 @@ class ha_innopart : public ha_innobase,
11141114

11151115
int records(ha_rows *num_rows) override;
11161116

1117-
int records_from_index(ha_rows *num_rows, uint) override {
1118-
/* Force use of cluster index until we implement sec index parallel scan. */
1119-
return ha_innopart::records(num_rows);
1120-
}
1121-
11221117
int index_next(uchar *record) override {
11231118
return (Partition_helper::ph_index_next(record));
11241119
}

0 commit comments

Comments
 (0)