Uploaded image for project: 'MariaDB Server'
  1. MariaDB Server
  2. MDEV-465

Optimizer : wrong index choice, leading to strong performances issues

Details

    Description

      Hi,

      I'm recreating in JIRA a Launchpad bug opened 2 years ago (https://bugs.launchpad.net/maria/+bug/639949), which is itself a follow up of a really annoying MySQL optimiser bug opened 4 years ago (http://bugs.mysql.com/bug.php?id=36817)

      To summarize, there are several simple cases where MySQL optimiser doesn't select the right index. This entails strong performance issues (especially when filesorting is involved), and force the developers to hack their applications, using USE INDEX (when it's possible...).

      Hoping someone finally takes a look at this serious issue...
      Actually it could also help some of my customers to switch to mariadb, because they are also a little bit tired to put USE INDEX everywhere in there code

      Thanks and regards,
      Jocelyn Fournier

      Attachments

        Issue Links

          Activity

            Trying the original testcase from http://bugs.mysql.com/bug.php?id=36817:

            Clean MariaDB 10.1:

            MariaDB [j11]> CREATE TABLE `a` (
                ->   `id1` int(10) unsigned NOT NULL auto_increment,
                ->   `id2` tinyint(3) unsigned NOT NULL default '0',
                ->   `id3` tinyint(3) unsigned NOT NULL default '0',
                ->   `id4` int(10) unsigned NOT NULL default '0',
                ->   `date` timestamp NOT NULL default CURRENT_TIMESTAMP,
                ->   PRIMARY KEY  (`id1`),
                ->   KEY `id2` (`id2`,`id3`,`id4`,`date`),
                ->   KEY `id2_2` (`id2`,`id3`,`date`)
                -> ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
            Query OK, 0 rows affected (0.08 sec)
             
            MariaDB [j11]> INSERT INTO a (id2,id3,id4) VALUES (1,1,1),(1,1,1),(1,1,1),(1,1,1),(1,0,1),(1,2,1),(1,3,1);
            Query OK, 7 rows affected (0.01 sec)
            Records: 7  Duplicates: 0  Warnings: 0
             
            MariaDB [j11]> EXPLAIN SELECT id1 FROM a WHERE id2=1 AND id3=1 ORDER BY date DESC LIMIT 0,4;
            +------+-------------+-------+------+---------------+------+---------+-------------+------+-----------------------------+
            | id   | select_type | table | type | possible_keys | key  | key_len | ref         | rows | Extra                       |
            +------+-------------+-------+------+---------------+------+---------+-------------+------+-----------------------------+
            |    1 | SIMPLE      | a     | ref  | id2,id2_2     | id2  | 2       | const,const |    3 | Using where; Using filesort |
            +------+-------------+-------+------+---------------+------+---------+-------------+------+-----------------------------+
             
            MariaDB [j11]> DROP TABLE IF EXISTS a;
            MariaDB [j11]> CREATE TABLE `a` (
                ->   `id1` int(10) unsigned NOT NULL auto_increment,
                ->   `id2` tinyint(3) unsigned NOT NULL default '0',
                ->   `id3` tinyint(3) unsigned NOT NULL default '0',
                ->   `id4` int(10) unsigned NOT NULL default '0',
                ->   `date` timestamp NOT NULL default CURRENT_TIMESTAMP,
                ->   PRIMARY KEY  (`id1`),
                ->   KEY `id2` (`id2`,`id3`,`date`),
                ->   KEY `id2_2` (`id2`,`id3`,`id4`,`date`)
                -> ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
            Query OK, 0 rows affected (0.06 sec)
             
            MariaDB [j11]> INSERT INTO a (id2,id3,id4) VALUES (1,1,1),(1,1,1),(1,1,1),(1,1,1),(1,0,1),(1,2,1),(1,3,1);
            Query OK, 7 rows affected (0.00 sec)
            Records: 7  Duplicates: 0  Warnings: 0
             
            MariaDB [j11]> EXPLAIN SELECT id1 FROM a WHERE id2=1 AND id3=1 ORDER BY date DESC LIMIT 0,4;
            +------+-------------+-------+------+---------------+------+---------+-------------+------+-------------+
            | id   | select_type | table | type | possible_keys | key  | key_len | ref         | rows | Extra       |
            +------+-------------+-------+------+---------------+------+---------+-------------+------+-------------+
            |    1 | SIMPLE      | a     | ref  | id2,id2_2     | id2  | 2       | const,const |    3 | Using where |
            +------+-------------+-------+------+---------------+------+---------+-------------+------+-------------+

            10.1 tree with fixes for MDEV-6384, MDEV-6480:

            MariaDB [j11]> CREATE TABLE `a` (
                ->   `id1` int(10) unsigned NOT NULL auto_increment,
                ->   `id2` tinyint(3) unsigned NOT NULL default '0',
                ->   `id3` tinyint(3) unsigned NOT NULL default '0',
                ->   `id4` int(10) unsigned NOT NULL default '0',
                ->   `date` timestamp NOT NULL default CURRENT_TIMESTAMP,
                ->   PRIMARY KEY  (`id1`),
                ->   KEY `id2` (`id2`,`id3`,`id4`,`date`),
                ->   KEY `id2_2` (`id2`,`id3`,`date`)
                -> ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
            Query OK, 0 rows affected (0.12 sec)
             
            MariaDB [j11]> INSERT INTO a (id2,id3,id4) VALUES (1,1,1),(1,1,1),(1,1,1),(1,1,1),(1,0,1),(1,2,1),(1,3,1);
            Query OK, 7 rows affected (0.00 sec)
            Records: 7  Duplicates: 0  Warnings: 0
             
            MariaDB [j11]> EXPLAIN SELECT id1 FROM a WHERE id2=1 AND id3=1 ORDER BY date DESC LIMIT 0,4;
            +------+-------------+-------+-------+---------------+-------+---------+------+------+-------------+
            | id   | select_type | table | type  | possible_keys | key   | key_len | ref  | rows | Extra       |
            +------+-------------+-------+-------+---------------+-------+---------+------+------+-------------+
            |    1 | SIMPLE      | a     | range | id2,id2_2     | id2_2 | 2       | NULL |    3 | Using where |
            +------+-------------+-------+-------+---------------+-------+---------+------+------+-------------+
             
            MariaDB [j11]> DROP TABLE IF EXISTS a;
            Query OK, 0 rows affected (0.00 sec)
             
            MariaDB [j11]> CREATE TABLE `a` (
                ->   `id1` int(10) unsigned NOT NULL auto_increment,
                ->   `id2` tinyint(3) unsigned NOT NULL default '0',
                ->   `id3` tinyint(3) unsigned NOT NULL default '0',
                ->   `id4` int(10) unsigned NOT NULL default '0',
                ->   `date` timestamp NOT NULL default CURRENT_TIMESTAMP,
                ->   PRIMARY KEY  (`id1`),
                ->   KEY `id2` (`id2`,`id3`,`date`),
                ->   KEY `id2_2` (`id2`,`id3`,`id4`,`date`)
                -> ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
            Query OK, 0 rows affected (0.07 sec)
             
            MariaDB [j11]> INSERT INTO a (id2,id3,id4) VALUES (1,1,1),(1,1,1),(1,1,1),(1,1,1),(1,0,1),(1,2,1),(1,3,1);
            Query OK, 7 rows affected (0.00 sec)
            Records: 7  Duplicates: 0  Warnings: 0
             
            MariaDB [j11]> EXPLAIN SELECT id1 FROM a WHERE id2=1 AND id3=1 ORDER BY date DESC LIMIT 0,4;
            +------+-------------+-------+------+---------------+------+---------+-------------+------+-------------+
            | id   | select_type | table | type | possible_keys | key  | key_len | ref         | rows | Extra       |
            +------+-------------+-------+------+---------------+------+---------+-------------+------+-------------+
            |    1 | SIMPLE      | a     | ref  | id2,id2_2     | id2  | 2       | const,const |    3 | Using where |
            +------+-------------+-------+------+---------------+------+---------+-------------+------+-------------+

            psergei Sergei Petrunia added a comment - Trying the original testcase from http://bugs.mysql.com/bug.php?id=36817: Clean MariaDB 10.1: MariaDB [j11]> CREATE TABLE `a` ( -> `id1` int(10) unsigned NOT NULL auto_increment, -> `id2` tinyint(3) unsigned NOT NULL default '0', -> `id3` tinyint(3) unsigned NOT NULL default '0', -> `id4` int(10) unsigned NOT NULL default '0', -> `date` timestamp NOT NULL default CURRENT_TIMESTAMP, -> PRIMARY KEY (`id1`), -> KEY `id2` (`id2`,`id3`,`id4`,`date`), -> KEY `id2_2` (`id2`,`id3`,`date`) -> ) ENGINE=MyISAM DEFAULT CHARSET=latin1; Query OK, 0 rows affected (0.08 sec)   MariaDB [j11]> INSERT INTO a (id2,id3,id4) VALUES (1,1,1),(1,1,1),(1,1,1),(1,1,1),(1,0,1),(1,2,1),(1,3,1); Query OK, 7 rows affected (0.01 sec) Records: 7 Duplicates: 0 Warnings: 0   MariaDB [j11]> EXPLAIN SELECT id1 FROM a WHERE id2=1 AND id3=1 ORDER BY date DESC LIMIT 0,4; +------+-------------+-------+------+---------------+------+---------+-------------+------+-----------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +------+-------------+-------+------+---------------+------+---------+-------------+------+-----------------------------+ | 1 | SIMPLE | a | ref | id2,id2_2 | id2 | 2 | const,const | 3 | Using where; Using filesort | +------+-------------+-------+------+---------------+------+---------+-------------+------+-----------------------------+   MariaDB [j11]> DROP TABLE IF EXISTS a; MariaDB [j11]> CREATE TABLE `a` ( -> `id1` int(10) unsigned NOT NULL auto_increment, -> `id2` tinyint(3) unsigned NOT NULL default '0', -> `id3` tinyint(3) unsigned NOT NULL default '0', -> `id4` int(10) unsigned NOT NULL default '0', -> `date` timestamp NOT NULL default CURRENT_TIMESTAMP, -> PRIMARY KEY (`id1`), -> KEY `id2` (`id2`,`id3`,`date`), -> KEY `id2_2` (`id2`,`id3`,`id4`,`date`) -> ) ENGINE=MyISAM DEFAULT CHARSET=latin1; Query OK, 0 rows affected (0.06 sec)   MariaDB [j11]> INSERT INTO a (id2,id3,id4) VALUES (1,1,1),(1,1,1),(1,1,1),(1,1,1),(1,0,1),(1,2,1),(1,3,1); Query OK, 7 rows affected (0.00 sec) Records: 7 Duplicates: 0 Warnings: 0   MariaDB [j11]> EXPLAIN SELECT id1 FROM a WHERE id2=1 AND id3=1 ORDER BY date DESC LIMIT 0,4; +------+-------------+-------+------+---------------+------+---------+-------------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +------+-------------+-------+------+---------------+------+---------+-------------+------+-------------+ | 1 | SIMPLE | a | ref | id2,id2_2 | id2 | 2 | const,const | 3 | Using where | +------+-------------+-------+------+---------------+------+---------+-------------+------+-------------+ 10.1 tree with fixes for MDEV-6384 , MDEV-6480 : MariaDB [j11]> CREATE TABLE `a` ( -> `id1` int(10) unsigned NOT NULL auto_increment, -> `id2` tinyint(3) unsigned NOT NULL default '0', -> `id3` tinyint(3) unsigned NOT NULL default '0', -> `id4` int(10) unsigned NOT NULL default '0', -> `date` timestamp NOT NULL default CURRENT_TIMESTAMP, -> PRIMARY KEY (`id1`), -> KEY `id2` (`id2`,`id3`,`id4`,`date`), -> KEY `id2_2` (`id2`,`id3`,`date`) -> ) ENGINE=MyISAM DEFAULT CHARSET=latin1; Query OK, 0 rows affected (0.12 sec)   MariaDB [j11]> INSERT INTO a (id2,id3,id4) VALUES (1,1,1),(1,1,1),(1,1,1),(1,1,1),(1,0,1),(1,2,1),(1,3,1); Query OK, 7 rows affected (0.00 sec) Records: 7 Duplicates: 0 Warnings: 0   MariaDB [j11]> EXPLAIN SELECT id1 FROM a WHERE id2=1 AND id3=1 ORDER BY date DESC LIMIT 0,4; +------+-------------+-------+-------+---------------+-------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +------+-------------+-------+-------+---------------+-------+---------+------+------+-------------+ | 1 | SIMPLE | a | range | id2,id2_2 | id2_2 | 2 | NULL | 3 | Using where | +------+-------------+-------+-------+---------------+-------+---------+------+------+-------------+   MariaDB [j11]> DROP TABLE IF EXISTS a; Query OK, 0 rows affected (0.00 sec)   MariaDB [j11]> CREATE TABLE `a` ( -> `id1` int(10) unsigned NOT NULL auto_increment, -> `id2` tinyint(3) unsigned NOT NULL default '0', -> `id3` tinyint(3) unsigned NOT NULL default '0', -> `id4` int(10) unsigned NOT NULL default '0', -> `date` timestamp NOT NULL default CURRENT_TIMESTAMP, -> PRIMARY KEY (`id1`), -> KEY `id2` (`id2`,`id3`,`date`), -> KEY `id2_2` (`id2`,`id3`,`id4`,`date`) -> ) ENGINE=MyISAM DEFAULT CHARSET=latin1; Query OK, 0 rows affected (0.07 sec)   MariaDB [j11]> INSERT INTO a (id2,id3,id4) VALUES (1,1,1),(1,1,1),(1,1,1),(1,1,1),(1,0,1),(1,2,1),(1,3,1); Query OK, 7 rows affected (0.00 sec) Records: 7 Duplicates: 0 Warnings: 0   MariaDB [j11]> EXPLAIN SELECT id1 FROM a WHERE id2=1 AND id3=1 ORDER BY date DESC LIMIT 0,4; +------+-------------+-------+------+---------------+------+---------+-------------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +------+-------------+-------+------+---------------+------+---------+-------------+------+-------------+ | 1 | SIMPLE | a | ref | id2,id2_2 | id2 | 2 | const,const | 3 | Using where | +------+-------------+-------+------+---------------+------+---------+-------------+------+-------------+

            That is, the fix for MDEV-6384 fixes this issue.

            psergei Sergei Petrunia added a comment - That is, the fix for MDEV-6384 fixes this issue.

            Hi Sergei,

            The explain

            MariaDB [j11]> EXPLAIN SELECT id1 FROM a WHERE id2=1 AND id3=1 ORDER BY date DESC LIMIT 0,4;
            +------+-------------+-------+-------+---------------+-------+---------+------+------+-------------+
            | id   | select_type | table | type  | possible_keys | key   | key_len | ref  | rows | Extra       |
            +------+-------------+-------+-------+---------------+-------+---------+------+------+-------------+
            |    1 | SIMPLE      | a     | range | id2,id2_2     | id2_2 | 2       | NULL |    3 | Using where |
            +------+-------------+-------+-------+---------------+-------+---------+------+------+-------------+

            looks weird.
            Why a range access is used here with id2_2, instead of ref ? (although no more filesort is used, which is great !)

            jocel1 jocelyn fournier added a comment - Hi Sergei, The explain MariaDB [j11]> EXPLAIN SELECT id1 FROM a WHERE id2=1 AND id3=1 ORDER BY date DESC LIMIT 0,4; +------+-------------+-------+-------+---------------+-------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +------+-------------+-------+-------+---------------+-------+---------+------+------+-------------+ | 1 | SIMPLE | a | range | id2,id2_2 | id2_2 | 2 | NULL | 3 | Using where | +------+-------------+-------+-------+---------------+-------+---------+------+------+-------------+ looks weird. Why a range access is used here with id2_2, instead of ref ? (although no more filesort is used, which is great !)

            range and ref(const) are for the most part the same thing. Code for range access is able to scan arbitrary ranges, code for ref access handles lookups on tbl.key=expr, where expr can also be constant.

            Internally, ref(const) is converted into range in most cases (or maybe even all cases).

            Here, we use index to read rows in order. We can use arbitrary range access, but not arbitrary ref access. that's why ORDER BY optimizer switches to range access. ref access is constructed by the join optimizer. however, ORDER BY optimizer is invoked after join optimizer, so range does not get replaced with ref. But, as I said, there is hardly any difference.

            psergei Sergei Petrunia added a comment - range and ref(const) are for the most part the same thing. Code for range access is able to scan arbitrary ranges, code for ref access handles lookups on tbl.key=expr, where expr can also be constant. Internally, ref(const) is converted into range in most cases (or maybe even all cases). Here, we use index to read rows in order. We can use arbitrary range access, but not arbitrary ref access. that's why ORDER BY optimizer switches to range access. ref access is constructed by the join optimizer. however, ORDER BY optimizer is invoked after join optimizer, so range does not get replaced with ref. But, as I said, there is hardly any difference.

            Fixed in 10.1 by fix for MDEV-6384.

            psergei Sergei Petrunia added a comment - Fixed in 10.1 by fix for MDEV-6384 .

            People

              psergei Sergei Petrunia
              joce jocelyn fournier
              Votes:
              0 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:

                Git Integration

                  Error rendering 'com.xiplink.jira.git.jira_git_plugin:git-issue-webpanel'. Please contact your Jira administrators.