Bug #84366 | InnoDB index dives do not detect concurrent tree changes, return bogus estimates | ||
---|---|---|---|
Submitted: | 29 Dec 2016 6:39 | Modified: | 1 Feb 2018 10:51 |
Reporter: | Laurynas Biveinis (OCA) | Email Updates: | |
Status: | Verified | Impact on me: | |
Category: | MySQL Server: InnoDB storage engine | Severity: | S3 (Non-critical) |
Version: | 5.6+ | OS: | Any |
Assigned to: | CPU Architecture: | Any | |
Tags: | index dive, innodb, range optimizer |
[29 Dec 2016 6:39]
Laurynas Biveinis
[29 Dec 2016 7:38]
MySQL Verification Team
Hello Laurynas, Thank you for the report and test case. Verified as described with 5.6.35 source build. Thanks, Umesh
[17 Jan 2017 4:17]
Laurynas Biveinis
Bug 84366 fix for 5.6 (*) I confirm the code being submitted is offered under the terms of the OCA, and that I am authorized to contribute it.
Contribution: bug84366-5.6.patch (application/octet-stream, text), 14.06 KiB.
[17 Jan 2017 4:17]
Laurynas Biveinis
Bug 84366 fix for 5.7 (*) I confirm the code being submitted is offered under the terms of the OCA, and that I am authorized to contribute it.
Contribution: bug84366-5.7.patch (application/octet-stream, text), 11.12 KiB.
[17 Jan 2017 4:17]
Laurynas Biveinis
Bug 84366 fix for 8.0.0 (*) I confirm the code being submitted is offered under the terms of the OCA, and that I am authorized to contribute it.
Contribution: bug84366-8.0.patch (application/octet-stream, text), 11.12 KiB.
[17 Jan 2017 4:22]
Laurynas Biveinis
The contributed fix for 5.6 backports the btr_estimate_n_rows_in_range restart support ("Fix Bug#20618309 ASSERT SLOT1->PAGE_LEVEL == SLOT2->PAGE_LEVEL, BTR_ESTIMATE_N_ROWS_IN_RANGE()") and extends it to restart when the two paths have 1) crossed and 2) point to the same page and 3) that same page apparently has different number of records in the two paths. 5.7 and 8.0.0 patches are smaller as they don't need the backport. If nothing else, please apply the mysql-test/include/* part, which stabilises the testsuite (spurious index_merge_innodb failures). While the code part makes InnoDB more robust for queries in parallel with purge, the testsuite patch removes the concurrent purge altogether.
[17 Jan 2017 4:24]
Laurynas Biveinis
The patch also adds an early zero return from estimate when paths cross instead of merely resetting n_rows to zero. This looks correct to me but I might be missing something.
[3 Mar 2017 4:57]
Laurynas Biveinis
There is one more index_merge_instability: main.index_merge_innodb w2 [ fail ] Test ended at 2017-01-11 08:54:34 CURRENT_TEST: main.index_merge_innodb --- /mnt/workspace/percona-server-5.6-trunk/BUILD_TYPE/debug/Host/ubuntu-xenial-32bit/mysql-test/r/index_merge_innodb.result 2017-01-03 15:06:26.917177432 +0300 +++ /mnt/workspace/percona-server-5.6-trunk/BUILD_TYPE/debug/Host/ubuntu-xenial-32bit/build/mysql-test/var/2/log/index_merge_innodb.reject 2017-01-11 16:54:33.476707245 +0300 @@ -698,7 +698,7 @@ key1 key2 filler1 explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge key1,key2,key3,key4 key1,key2,key3,key4 5,5,5,5 NULL 4 Using union(intersect(key1,key2),intersect(key3,key4)); Using where +1 SIMPLE t1 index_merge key1,key2,key3,key4 key1,key2,key4,key3 5,5,5,5 NULL 4 Using union(intersect(key1,key2),intersect(key4,key3)); Using where select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; key1 key2 key3 key4 filler1 -1 -1 100 100 key4-key3 mysqltest: Result content mismatch It is also preceded by a delete from a secondary index, thus purge may be running concurrently with the query. This could be solved with a slow shutdown server restart, but here key3 and key4 are interchangeable, thus I'd just mask them both to something common. Re-uploading the patches with the following snippet added. diff --git a/mysql-test/include/index_merge_ror.inc b/mysql-test/include/index_merge_ror.inc index bd2a781a748..f48d47bc67d 100644 --- a/mysql-test/include/index_merge_ror.inc +++ b/mysql-test/include/index_merge_ror.inc @@ -178,6 +178,7 @@ select key1,key2,filler1 from t1 where key2=100 and key2=200; # ROR-union(ROR-intersection) with one of ROR-intersection giving empty # results +--replace_result key3 key34 key4 key34 explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; diff --git a/mysql-test/r/index_merge_innodb.result b/mysql-test/r/index_merge_innodb.result index 85d15f77489..5494d86ad5c 100644 --- a/mysql-test/r/index_merge_innodb.result +++ b/mysql-test/r/index_merge_innodb.result @@ -696,9 +696,9 @@ update t1 set key1=200,key2=200 where key1=100 and key2=100; delete from t1 where key1=200 and key2=200; select key1,key2,filler1 from t1 where key2=100 and key2=200; key1 key2 filler1 -explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; +explain select key1,key2,key34,key34,filler1 from t1 where key1=100 and key2=100 or key34=100 and key34=100; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge key1,key2,key3,key4 key1,key2,key3,key4 5,5,5,5 NULL 4 Using union(intersect(key1,key2),intersect(key3,key4)); Using where +1 SIMPLE t1 index_merge key1,key2,key34,key34 key1,key2,key34,key34 5,5,5,5 NULL 4 Using union(intersect(key1,key2),intersect(key34,key34)); Using where select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; key1 key2 key3 key4 filler1 -1 -1 100 100 key4-key3 diff --git a/mysql-test/r/index_merge_myisam.result b/mysql-test/r/index_merge_myisam.result index 505b59a43dc..e193d5d6511 100644 --- a/mysql-test/r/index_merge_myisam.result +++ b/mysql-test/r/index_merge_myisam.result @@ -726,9 +726,9 @@ update t1 set key1=200,key2=200 where key1=100 and key2=100; delete from t1 where key1=200 and key2=200; select key1,key2,filler1 from t1 where key2=100 and key2=200; key1 key2 filler1 -explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; +explain select key1,key2,key34,key34,filler1 from t1 where key1=100 and key2=100 or key34=100 and key34=100; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge key1,key2,key3,key4 key1,key2,key3,key4 5,5,5,5 NULL 152 Using union(intersect(key1,key2),intersect(key3,key4)); Using where +1 SIMPLE t1 index_merge key1,key2,key34,key34 key1,key2,key34,key34 5,5,5,5 NULL 152 Using union(intersect(key1,key2),intersect(key34,key34)); Using where select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; key1 key2 key3 key4 filler1 -1 -1 100 100 key4-key3
[3 Mar 2017 5:01]
Laurynas Biveinis
I cannot upload the refreshed contribution patches, because the existing contributions are Accepted (thanks!). In that case the above comment should contain enough information
[14 Apr 2017 9:37]
Laurynas Biveinis
Bug 84366 fix for 8.0.1
Attachment: bug84366-8.0.1.patch (application/octet-stream, text), 14.42 KiB.
[4 Aug 2017 19:40]
Laurynas Biveinis
Bug 84366 fix for 8.0.2
Attachment: bug84366-8.0.2.patch (application/octet-stream, text), 14.42 KiB.
[1 Feb 2018 10:51]
Laurynas Biveinis
The latest contributed fix applies cleanly and works on 8.0.4 too.
[13 Jun 2018 12:19]
Laurynas Biveinis
Bug 84366 fix for 8.0.11
Attachment: bug84366-8.0.11.patch (application/octet-stream, text), 14.57 KiB.