0

I have a table for Items and then a table for Parameters where each Item can have multiple Parameters. Each Parameter object has a foreign key back to its Item. I also have a Parameter Type table that stores the possible types of Parameters.

Here is the table info for my Parameter table:

CREATE TABLE 'parameter' (
  'id' int(11) NOT NULL AUTO_INCREMENT,
  'type_id' int(11) NOT NULL,
  'value' longtext NOT NULL,
  'item_id' int(11) NOT NULL,
  PRIMARY KEY ('id'),
  KEY 'parameter_403d8ff3' ('type_id'),
  KEY 'parameter_0a47aae8' ('item_id'),
  CONSTRAINT 'item_id_refs_id_eeb3b028' FOREIGN KEY ('item_id') REFERENCES 'tracker_item' ('id'),
  CONSTRAINT 'type_id_refs_id_53b2638a' FOREIGN KEY ('type_id') REFERENCES 'parametertype' ('id'),
) ENGINE=InnoDB AUTO_INCREMENT=31445609 DEFAULT CHARSET=utf8;

And here is my Parameter Type table:

CREATE TABLE 'parametertype' (
  'id' int(11) NOT NULL AUTO_INCREMENT,
  'name' varchar(60) NOT NULL,
  PRIMARY KEY ('id'),
  UNIQUE KEY 'name' ('name'),
) ENGINE=InnoDB AUTO_INCREMENT=309 DEFAULT CHARSET=utf8;

I have two Items, IDs 115711 and 116792, for which I want to do this query:

SELECT p.`id`,
       p.`type_id`,
       p.`value`,
       p.`item_id`,
       p.`upload_id`,
       p.`creator_id`,
       p.`date_recorded`,
       p.`date_last_modified`,
       p.`date_added`
FROM parameter p
INNER JOIN parametertype pt ON p.`type_id` = pt.`id`
WHERE p.`item_id` = <ITEM_ID> 
  AND pt.`name` LIKE 'some_name' 
ORDER BY p.`date_recorded` DESC

When I do this for Item 116792, it takes 5.7ms. When I do it for Item 115711, it takes 9 SECONDS. The EXPLAIN of each query is the same except for the "ref" column -- for the fast query, it shows const in that column for the parameter table entry, where as for the slow query, it shows parametertype.id. Also, in the key column. The slow query shows data_parameter_403d8ff3 there (the key for the Parameter Type table) whereas the fast query shows data_parameter_0a47aae8 there (the key for the Item table).

What does this mean and why is one so slow? Is there anything I can do to make it as fast as the other query?

For context, Item 116792 has 560 Parameter entries and Item 115711 has 823 Parameter entries. The Parameter Type table has 237 entries.

The full EXPLAIN query for Item 116792:

    +----+-------------+--------------------+-------+-------------------------------------------------+-------------------------+---------+-------+------+-----------------------------------------------------------+
    | id | select_type | table              | type  | possible_keys                                   | key                     | key_len | ref   | rows | Extra                                                     |
    +----+-------------+--------------------+-------+-------------------------------------------------+-------------------------+---------+-------+------+-----------------------------------------------------------+
    |  1 | SIMPLE      | parametertype      | range | PRIMARY,name                                    | name                    | 182     | NULL  |    1 | Using where; Using index; Using temporary; Using filesort |
    |  1 | SIMPLE      | parameter          | ref   | parameter_403d8ff3,parameter_0a47aae8           | parameter_0a47aae8      | 4       | const |  559 | Using where                                               |
    +----+-------------+--------------------+-------+-------------------------------------------------+-------------------------+---------+-------+------+-----------------------------------------------------------+

The full EXPLAIN query for Item 115711:

    +----+-------------+--------------------+-------+-------------------------------------------------+-------------------------+---------+-------------------------------+------+-----------------------------------------------------------+
    | id | select_type | table              | type  | possible_keys                                   | key                     | key_len | ref                           | rows | Extra                                                     |
    +----+-------------+--------------------+-------+-------------------------------------------------+-------------------------+---------+-------------------------------+------+-----------------------------------------------------------+
    |  1 | SIMPLE      | parametertype      | range | PRIMARY,name                                    | name                    | 182     | NULL                          |    1 | Using where; Using index; Using temporary; Using filesort |
    |  1 | SIMPLE      | parameter          | ref   | parameter_403d8ff3,parameter_0a47aae8           | parameter_403d8ff3      | 4       | parametertype.id              |  676 | Using where                                               |
    +----+-------------+--------------------+-------+-------------------------------------------------+-------------------------+---------+-------------------------------+------+-----------------------------------------------------------+
  • Did you try running the query with and without cache? https://dev.mysql.com/doc/refman/5.0/en/query-cache-in-select.html – Craig Efrein Aug 06 '15 at 08:25
  • Thanks for the suggestion, but that didn't seem to affect it – samskeller Aug 06 '15 at 08:32
  • It was just to get a better idea of the true time each query takes – Craig Efrein Aug 06 '15 at 08:37
  • You might also want to check your innodb configuration, if you haven't done so already. Doesn't help with your query, but might speed things up globally. http://dba.stackexchange.com/questions/27328/how-large-should-be-mysql-innodb-buffer-pool-size/27341#27341 – Craig Efrein Aug 06 '15 at 08:40
  • Are you really sure pan from EXPLAIN is the same? Aren't the rows swapped or something? For the optimizer to use parametertype.id it has to know it, so read pt first, the other plan seems to use the const from the query itself. You can try EXPLAIN EXTENDED <query>; SHOW WARNINGS; too to see a bit more. – jkavalik Aug 06 '15 at 11:32
  • Apologies, there is one other difference -- in the key column. The slow query shows data_parameter_403d8ff3 there (the key for the Parameter Type table) whereas the fast query shows data_parameter_0a47aae8 there (the key for the Item table. What does that mean? I don't see any row swapping, though – samskeller Aug 06 '15 at 11:57
  • Seems like you have some unstable statistics and depending how many parameters there are for a given item and how many types of a given name, optimizer switches two different plans. You could try running ANALYZE TABLE, but on InnoDB it will probably not have a big effect. Do you need the LIKE for pt.name ? Do you use any wildcards? Maybe using = instead might help the optimizer to decide better. – jkavalik Aug 06 '15 at 12:08
  • Yeah I don't need the LIKE, and I can certainly refactor things so that I don't need it, but I was just wondering why it was like that... is there anyway to force a specific optimization plan? – samskeller Aug 06 '15 at 12:13
  • You can hint with USE/FORCE/IGNORE INDEX or you can add a multicolumn index which will be good enough for the optimizer to use always - give it an index to use for ORDER BY too - (item_id, date_recorded) on parameter table seems like a good choice - it can be used to skip a filesort so will have a big priority probably - try to add it and then test explains and times with and without it using USE/IGNORE. – jkavalik Aug 06 '15 at 13:03
  • Thanks @jkavalik -- looks like doing a USE on the existing Item index was enough to make the slow query speed up. Thanks! – samskeller Aug 07 '15 at 08:37

1 Answers1

0
ALTER TABLE parameter ADD INDEX(item_id, date_recorded)

Please provide EXPLAIN SELECT ... for both the slow and fast queries.

Rick James
  • 78,038
  • 5
  • 47
  • 113
  • Thanks, I've updated the description to include the full output of the EXPLAIN queries – samskeller Aug 06 '15 at 20:23
  • Added the index and used "USE INDEX" and that appears to have worked! In fact, it appears that even if I just use the existing Item Index that it goes as fast as it should. Thanks! – samskeller Aug 07 '15 at 08:37
  • @samskeller probably your query is selecting only a few rows so filesort is not slow - but this index is better and should work without the USE INDEX – jkavalik Aug 07 '15 at 10:13
  • 1
    Even faster might be INDEX(item_id, type_id, date_recorded) or INDEX(type_id, item_id, date_recorded) – Rick James Aug 07 '15 at 15:51