Bug #100191 macros like COND_FILTER_EQUALITY cannot handle diverse workloads
Submitted: 12 Jul 2020 10:38 Modified: 13 Jul 2020 9:30
Reporter: Atish Agrawal Email Updates:
Status: Verified Impact on me:
None 
Category:MySQL Server: Optimizer Severity:S5 (Performance)
Version:5.7.30, 8.0.20 OS:Any
Assigned to: CPU Architecture:Any

[12 Jul 2020 10:38] Atish Agrawal
Description:
I have been investigating a query plan regression seen when migrating to 8.0
for 5.6. It is a pretty substantial regression that started taking 1500 seconds versus 2 seconds in 5.6.

Root cause was COND_FILTER_EQUALITY, COND_FILTER_INEQUALITY and COND_FILTER_BETWEEN were introduced as a part of patch https://github.com/mysql/mysql server/commit/063734feff5d54b323e3360fcebd983556cf2e3f. This is prone to cause regression in query plans on tables that do not contain a histogram. It would be
nice if there are no regressions for tables that do not have a histogram. This is
especially painful when upgrading the server to 8.0 with workloads running against 5.6 servers. It is unlikely that the workloads will have the distribution similar to COND_FILTER_EQUALITY, COND_FILTER_INEQUALITY and COND_FILTER_BETWEEN.

How to repeat:
Sample repro mysqltest script: 

create table t1(a int primary key, b int, c int, key(b));
create table t2(a int primary key, b int, c int, unique key(b));

# Insert 10000 rows in t1 and 100 rows in t2
--disable_query_log
let $t1_count= 10000;
--echo # Insert $t1_count rows. Query log disabled.
while ($t1_count)
{
  --eval INSERT INTO t1(a,b,c) VALUES ($t1_count, $t1_count/50, null);
  dec $t1_count;
}

let $t2_count= 100;
--echo # Insert $t2_count rows. Query log disabled.
while ($t2_count)
{
  --eval INSERT INTO t2(a,b,c) VALUES ($t2_count, $t2_count, $t2_count);
  dec $t2_count;
}

--enable_query_log
ANALYZE TABLE t1;
ANALYZE TABLE t2;

EXPLAIN select count(*) from t1 join t2 using (b) where t1.c is null and t2.c <> 0;
select count(*) from t1 join t2 using (b) where t1.c is null and t2.c <> 0;

drop table t1;
drop table t2;

Output Plan:

EXPLAIN select count(*) from t1 join t2 using (b) where t1.c is null and t2.c <> 0;
id      select_type     table   partitions      type    possible_keys   key     key_len ref     rows    filtered        Extra
1       SIMPLE  t1      NULL    ALL     b       NULL    NULL    NULL    10000   10.00   Using where
1       SIMPLE  t2      NULL    eq_ref  b       b       5       test.t1.b       1       90.00   Using where

This query plan iterates over 10000 T1 rows because cost based estimation estimates that only 10% will satisfy "t1.c is null" predicate. However during actual execution, all the rows fit the predicate.
[13 Jul 2020 9:30] MySQL Verification Team
Hello Atish,

Thank you for the report and test case.

regards,
Umesh