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

Wrong query plan for query with no PK

Details

    Description

      Found this while working on MDEV-14433:
      Found an interesting mismatch between query plans that depends on the index number:

      Upstream, MySQL 5.6

      CREATE TABLE t3(
        pk int primary key,
        a varchar(10) NOT NULL,   
        e int(11) DEFAULT 0,   
        KEY (a) 
      ) ENGINE=ROCKSDB DEFAULT CHARSET=utf8;
      

      insert into t3 values (1,1,1),(2,2,2);
      explain select a from t3 where a <'zzz';
      +----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
      | id | select_type | table | type  | possible_keys | key  | key_len | ref  | rows | Extra       |
      +----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
      |  1 | SIMPLE      | t3    | range | a             | a    | 32      | NULL |    2 | Using where |
      +----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
      

      CREATE TABLE t4(
        pk int,
        a varchar(10) NOT NULL,
        e int(11) DEFAULT 0,   
        KEY (a)
      ) ENGINE=ROCKSDB DEFAULT CHARSET=utf8;
      insert into t4 values (1,1,1),(2,2,2);
      

      explain select a from t4 where a <'zzz';
      +----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
      | id | select_type | table | type  | possible_keys | key  | key_len | ref  | rows | Extra       |
      +----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
      |  1 | SIMPLE      | t4    | range | a             | a    | 32      | NULL |    1 | Using where |
      +----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
      

      MariaDB:

      CREATE TABLE t3(
        pk int primary key,
        a varchar(10) NOT NULL,   
        e int(11) DEFAULT 0,   
        KEY (a) 
      ) ENGINE=ROCKSDB DEFAULT CHARSET=utf8;
      insert into t3 values (1,1,1),(2,2,2);
      

      explain select a from t3 where a <'zzz';
      +------+-------------+-------+-------+---------------+------+---------+------+------+-------------+
      | id   | select_type | table | type  | possible_keys | key  | key_len | ref  | rows | Extra       |
      +------+-------------+-------+-------+---------------+------+---------+------+------+-------------+
      |    1 | SIMPLE      | t3    | range | a             | a    | 32      | NULL |    1 | Using where |
      +------+-------------+-------+-------+---------------+------+---------+------+------+-------------+
      

      CREATE TABLE t4(
        pk int,
        a varchar(10) NOT NULL,
        e int(11) DEFAULT 0,   
        KEY (a)
      ) ENGINE=ROCKSDB DEFAULT CHARSET=utf8;
      insert into t4 values (1,1,1),(2,2,2);
      

      explain select a from t4 where a <'zzz';
      +------+-------------+-------+-------+---------------+------+---------+------+------+--------------------------+
      | id   | select_type | table | type  | possible_keys | key  | key_len | ref  | rows | Extra                    |
      +------+-------------+-------+-------+---------------+------+---------+------+------+--------------------------+
      |    1 | SIMPLE      | t4    | index | a             | a    | 32      | NULL |    0 | Using where; Using index |
      +------+-------------+-------+-------+---------------+------+---------+------+------+--------------------------+
      

      Attachments

        Issue Links

          Activity

            Debugging

            CREATE TABLE t4(
              pk int,
              a varchar(10) NOT NULL,
              e int(11) DEFAULT 0,   
              KEY (a)
            ) ENGINE=ROCKSDB DEFAULT CHARSET=utf8;
            

            in TABLE_SHARE::init_from_binary_frm_image, stepping into the

                   if (handler_file->index_flags(key, i, 0) & HA_KEYREAD_ONLY)
            

            call:

              myrocks::ha_rocksdb::index_flags (this=0x7fff6c01b7e8, inx=0, part=0, all_parts=false)
            

            There, we have

            (gdb) p table
              $33 = (TABLE *) 0x0
            (gdb) p table_share
              $34 = (TABLE_SHARE *) 0x7ffff41bd890
            (gdb) p table_share->primary_key
              $35 = 0
            

            That is,

            • we are called for inx=0, this KEY(a) which is a secondary key
            • there is a TABLE_SHARE object which has primary_key=0
            • so the code assumes it is called for the PK:

              if (inx == table_share->primary_key) {
            

            and returns an incorrect value.

            psergei Sergei Petrunia added a comment - Debugging CREATE TABLE t4( pk int, a varchar(10) NOT NULL, e int(11) DEFAULT 0, KEY (a) ) ENGINE=ROCKSDB DEFAULT CHARSET=utf8; in TABLE_SHARE::init_from_binary_frm_image, stepping into the if (handler_file->index_flags(key, i, 0) & HA_KEYREAD_ONLY) call: myrocks::ha_rocksdb::index_flags (this=0x7fff6c01b7e8, inx=0, part=0, all_parts=false) There, we have (gdb) p table $33 = (TABLE *) 0x0 (gdb) p table_share $34 = (TABLE_SHARE *) 0x7ffff41bd890 (gdb) p table_share->primary_key $35 = 0 That is, we are called for inx=0, this KEY(a) which is a secondary key there is a TABLE_SHARE object which has primary_key=0 so the code assumes it is called for the PK: if (inx == table_share->primary_key) { and returns an incorrect value.

            table_share->primary_key is set in TABLE_SHARE::init_from_binary_frm_image but
            the mentioned index_flags() call is made before that.

            There is a local variable

                uint primary_key= my_strcasecmp(system_charset_info, share->keynames.type_names[0],
                                                primary_key_name) ? MAX_KEY : 0;
            

            which is set before the index_flags() call.

            Condition to set share->primary_key:

                if (primary_key < MAX_KEY &&
            	(share->keys_in_use.is_set(primary_key)))
                {
                  share->primary_key= primary_key;
            

            psergei Sergei Petrunia added a comment - table_share->primary_key is set in TABLE_SHARE::init_from_binary_frm_image but the mentioned index_flags() call is made before that. There is a local variable uint primary_key= my_strcasecmp(system_charset_info, share->keynames.type_names[0], primary_key_name) ? MAX_KEY : 0; which is set before the index_flags() call. Condition to set share->primary_key: if (primary_key < MAX_KEY && (share->keys_in_use.is_set(primary_key))) { share->primary_key= primary_key;

            People

              psergei Sergei Petrunia
              psergei Sergei Petrunia
              Votes:
              0 Vote for this issue
              Watchers:
              1 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.