Question

I have two tables, app and pricehistory there is a primary index id on app which is an int on pricehistory i have two fields id_app (int), price(float) and dateup (date) and an unique index on "id_app, dateup"

i'm trying to get the latest (of date) price of an app :

select app.id,
       (  select price 
          from pricehistory 
          where id_app=app.id 
          order by dateup desc limit 1) 
from app 
where id=147

the explain select is kind of weird because it return 1 row but it still makes a filesort :

id  select_type        table        type   possible_keys            key      key_len   ref     rows  Extra      
1   PRIMARY            app          const  PRIMARY                  PRIMARY     4      const      1   
2   DEPENDENT SUBQUERY pricehistory ref    id_app,id_app_2,id_app_3 id_app      4      const      1  Using where; Using filesort

why does it need to filesort when there is only 1 row ? and why it's file sorting when i'm indexing all it need (id_app and dateup)

app has 1 million rows and i'm using innodb

edit: a sql fiddle explaining the problem:

http://sqlfiddle.com/#!2/085027/1

edit3 : a new fiddle with another request with the same problem : http://sqlfiddle.com/#!2/f7682/6

edit4: this fiddle ( http://sqlfiddle.com/#!2/2785c/2 ) shows that the query proposed doesn't work because it select all the data from pricehistory just to fetch the ones i want

Was it helpful?

Solution

Here's a quick rule of thumb for which order columns should go in an index:

  1. Columns referenced in the WHERE clause with an equality condition (=).
  2. Choose one of:

    a. Columns referenced in the ORDER BY clause.

    b. Columns referenced in a GROUP BY clause.

    c. Columns referenced in the WHERE clause with a range condition (!=, >, <, IN, BETWEEN, IS [NOT] NULL).

  3. Columns referenced in the SELECT-list.

See How to Design Indexes, Really.

In this case, I was able to remove the filesort with this index:

mysql> alter table pricehistory add  key bk1 (id_app, dateup, price_fr);

And here's the EXPLAIN, showing no filesort, and the improvement of "Using index":

mysql> explain select price_fr from pricehistory where id_app=1 order by dateup desc\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: pricehistory
         type: ref
possible_keys: bk1
          key: bk1
      key_len: 4
          ref: const
         rows: 1
        Extra: Using where; Using index

You can make this index UNIQUE if you want to.

I had to drop the other unique keys, to avoid confusing the optimizer.

OTHER TIPS

The two UNIQUE KEYs are causing the problem. I changed your fiddle to the following, and it works without a filesort:

CREATE TABLE IF NOT EXISTS `pricehistory` (
  `id_app` int(10) unsigned NOT NULL,
  `dateup` date NOT NULL,
  `price_fr` float NOT NULL DEFAULT '-1',
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`),
  UNIQUE KEY `id_app` (`id_app`,`dateup`,`price_fr`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=345 ;


INSERT INTO pricehistory
(id_app, price_fr,dateup)
VALUES
('1', '4.99', now()),
('2', '0.45', now());

The EXPLAIN gives:

ID    SELECT_TYPE    TABLE           TYPE    POSSIBLE_KEYS    KEY         KEY_LEN    REF    ROWS    EXTRA
1     SIMPLE         pricehistory    ref     id_app           id_app      4          const  1       Using where; Using index

There's no reason to use a UNIQUE KEY on both (id_app,dateup) and (id_app,price_fr,dateup), as they are redundant. I'm pretty confident that redundancy is making MySQL somehow uncertain of itself so that it errs on the side of doing a filesort.

The solution is to remove the unique to one of the indexes. It seems like if it's not useful it's better to not put the unique keyword. thanks to both of you

edit: damn, with a different query with 2 tables, the filesort is back : http://sqlfiddle.com/#!2/f7682/6

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top