October 3, 2006

MySQL Optimizer and Innodb Primary Key

Posted by peter

Innodb primary key is special in many senses and I was always wondering how well MySQL is integrated with Innodb to take advantage of these special features.

Lets see which things work and which things do not:

I used the following simple table for tests:

SQL:
  1. CREATE TABLE `innodb` (
  2.   `id` int(10) UNSIGNED NOT NULL,
  3.   `a` int(11) DEFAULT NULL,
  4.   PRIMARY KEY  (`id`),
  5.   KEY `a` (`a`)
  6. ) ENGINE=InnoDB DEFAULT CHARSET=latin1;

"myisam" is same table created with MyISAM storage engine used to show difference:

MySQL Optimizer correctly knows Innodb tables is clustered by primary key in the sense it would not be faster to do external filesort than to do lookups in primary key order:

SQL:
  1. mysql> EXPLAIN SELECT * FROM innodb ORDER BY id \G
  2. *************************** 1. row ***************************
  3.            id: 1
  4.   select_type: SIMPLE
  5.         TABLE: pktest
  6.          type: INDEX
  7. possible_keys: NULL
  8.           KEY: PRIMARY
  9.       key_len: 4
  10.           ref: NULL
  11.          rows: 6
  12.         Extra:
  13. 1 row IN SET (0.00 sec)
  14.  
  15. mysql> EXPLAIN SELECT * FROM myisam ORDER BY id \G
  16. *************************** 1. row ***************************
  17.            id: 1
  18.   select_type: SIMPLE
  19.         TABLE: myisam
  20.          type: ALL
  21. possible_keys: NULL
  22.           KEY: NULL
  23.       key_len: NULL
  24.           ref: NULL
  25.          rows: 6
  26.         Extra: USING filesort
  27. 1 row IN SET (0.00 sec)

MySQL Optimizer is also able to figure out every key also holds primary key value so primary key value can be read from index, making some queries index covered which previously was not: Notice "Using Index" difference

SQL:
  1. mysql> EXPLAIN SELECT id FROM innodb WHERE a=3 \G
  2. *************************** 1. row ***************************
  3.            id: 1
  4.   select_type: SIMPLE
  5.         TABLE: innodb
  6.          type: ref
  7. possible_keys: a
  8.           KEY: a
  9.       key_len: 5
  10.           ref: const
  11.          rows: 1
  12.         Extra: USING WHERE; USING INDEX
  13. 1 row IN SET (0.00 sec)
  14.  
  15. mysql> EXPLAIN SELECT id FROM myisam WHERE a=3 \G
  16. *************************** 1. row ***************************
  17.            id: 1
  18.   select_type: SIMPLE
  19.         TABLE: myisam
  20.          type: ref
  21. possible_keys: a
  22.           KEY: a
  23.       key_len: 5
  24.           ref: const
  25.          rows: 1
  26.         Extra: USING WHERE
  27. 1 row IN SET (0.00 sec)

MySQL However is unable to benefit from the fact each index internally has primary key as last column, so key on (a) is effectively key on (a,id) which means MySQL could skip filesort if ordering is done by primary key:

SQL:
  1. mysql> EXPLAIN SELECT id FROM innodb WHERE a=3 ORDER BY id \G
  2. *************************** 1. row ***************************
  3.            id: 1
  4.   select_type: SIMPLE
  5.         TABLE: innodb
  6.          type: ref
  7. possible_keys: a
  8.           KEY: a
  9.       key_len: 5
  10.           ref: const
  11.          rows: 1
  12.         Extra: USING WHERE; USING INDEX; USING filesort
  13. 1 row IN SET (0.00 sec)

Filesort should be avoided in this case which it is not. I now filed it as a
bug while I do not really think it would be fixed soon

Related posts: :Extended EXPLAIN::MySQL Optimizer team comments on TPC-H Results::How adding another table to JOIN can improve performance ?:
 

9 Comments »

  1. 1. Roland Volkmann

    Hello Peter,

    as long as the bug is not fixed, you can define key a as “KEY `a` (`a`,`id`)” to avoid filesort. I did so in my projects.

    With best regards

    Roland

    Comment :: October 4, 2006 @ 3:07 pm

  2. Roland yes. The solution you’re mentioning does work and it is a way to get such behavior for non-Innodb tables.
    My point is simply it could be done for Innodb with given index structure but it is not.

    Also quite curious if key (a,id) is used is Innodb is smart enough to notice it already had id in the end so it does not have to be added second time.

    Comment :: October 5, 2006 @ 12:30 am

  3. 3. grantsucceeded

    Peter:
    It is not true that primary key lookup is faster than filesort, or at least should not be true.

    If one is sorting a significant number of rows, sort is faster because it can do sequential IOs then O(logN) sort instead of random IOs.

    Comment :: October 27, 2006 @ 11:50 pm

  4. Why is that ?

    The choice is basically if you access data by primary key and send it or you access data by primary key to sort it and return back to the client ?

    Innodb full table scan will be reading via Innodb key and the data comes sorted already so it will be just overhead to sort it again.

    Comment :: October 28, 2006 @ 1:38 am

  5. Will Primary key improve performance ?

    Comment :: October 18, 2007 @ 6:12 am

  6. This is now fixed, at least my tests show so

    CREATE TABLE `pricesbig_inno` (
    `id` int(10) unsigned NOT NULL,
    `url_id` int(10) unsigned NOT NULL,
    `product_id` int(10) unsigned NOT NULL,
    PRIMARY KEY (`product_id`,`id`),
    KEY `id` (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

    mysql> EXPLAIN SELECT id, product_id FROM `pricesbig_inno` WHERE id =1515;
    +—-+————-+—————-+——+—————+——+———+——-+——+————-+
    | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
    +—-+————-+—————-+——+—————+——+———+——-+——+————-+
    | 1 | SIMPLE | pricesbig_inno | ref | id | id | 4 | const | 1 | Using index |
    +—-+————-+—————-+——+—————+——+———+——-+——+————-+
    1 row in set (0.00 sec)

    Comment :: March 23, 2008 @ 11:44 am

  7. What is fixed ?

    This seems to be similar to my example:

    #
    mysql> EXPLAIN SELECT id FROM innodb WHERE a=3 \G
    #
    *************************** 1. row ***************************
    #
    id: 1
    #
    select_type: SIMPLE
    #
    TABLE: innodb
    #
    type: ref
    #
    possible_keys: a
    #
    KEY: a
    #
    key_len: 5
    #
    ref: const
    #
    rows: 1
    #
    Extra: USING WHERE; USING INDEX
    #
    1 row IN SET (0.00 sec)

    Which already had using index.

    Comment :: March 23, 2008 @ 1:52 pm

  8. 8. Cyril Scetbon

    It seems to be not the case anymore in 5.1 :

    mysql> EXPLAIN SELECT id FROM innodb WHERE a=3 ORDER BY id \G
    *************************** 1. row ***************************
    id: 1
    select_type: SIMPLE
    table: innodb
    type: ref
    possible_keys: a
    key: a
    key_len: 5
    ref: const
    rows: 3
    Extra: Using where; Using index
    1 row in set (0.51 sec)

    Comment :: July 25, 2008 @ 6:44 am

  9. Cyril,

    Thank you for update. Indeed problems are getting fixed so you have to look at the old posts with care.
    In particular as developers often read this blog it is not a surprise :)

    Comment :: July 25, 2008 @ 10:44 am

 



Subscribe without commenting


This page was found by: innodb primary key mysql optimizer mysql read primary mysql external keys ... innodb primary key i...