2010-12-21 72 views
1

此查询不完全在合理时间内:Mysql的子查询极其缓慢(似乎不使用索引)

mysql> select * from prices where symbol='GOOG' and date in 
(select max(date) from prices where symbol='GOOG' and yearweek(date) > 201001 
group by yearweek(date)); 

“价格”是键关闭ID,并具有独特的二次(符号,日期)的指数:

mysql> show index from prices; 
+--------+------------+-----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
| Table | Non_unique | Key_name  | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | 
+--------+------------+-----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
| prices |   0 | PRIMARY   |   1 | id   | A   |  468915 |  NULL | NULL |  | BTREE  |   | 
| prices |   0 | SECONDARY_INDEX |   1 | date  | A   |  10905 |  NULL | NULL | YES | BTREE  |   | 
| prices |   0 | SECONDARY_INDEX |   2 | symbol  | A   |  468915 |  NULL | NULL | YES | BTREE  |   | 
+--------+------------+-----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
3 rows in set (0.00 sec) 

从寻找解释输出,它好像MySQL是不使用的索引(日期,符号)。 WHERE符号='GOOG'和日期IN(...))的组合是否需要全表扫描并且不使用次要唯一索引?

mysql> EXPLAIN select * from prices where symbol='GOOG' and date in (select max(date) from prices where symbol='GOOG' and yearweek(date) > 201001 group by yearweek(date)); 
+----+--------------------+--------+-------+---------------+-----------------+---------+------+--------+-----------------------------------------------------------+ 
| id | select_type  | table | type | possible_keys | key    | key_len | ref | rows | Extra              | 
+----+--------------------+--------+-------+---------------+-----------------+---------+------+--------+-----------------------------------------------------------+ 
| 1 | PRIMARY   | prices | ALL | NULL   | NULL   | NULL | NULL | 468915 | Using where            | 
| 2 | DEPENDENT SUBQUERY | prices | index | NULL   | SECONDARY_INDEX | 17  | NULL | 468915 | Using where; Using index; Using temporary; Using filesort | 
+----+--------------------+--------+-------+---------------+-----------------+---------+------+--------+-----------------------------------------------------------+ 
2 rows in set (0.00 sec) 
+0

看到我的答案在这里:http://stackoverflow.com/questions/8610325/mysql-select-with-in-clause-does-not-use-index – DanMan 2013-02-09 17:07:53

回答

2

尝试JOIN:

SELECT 
    prices.* 
FROM 
    prices 
     JOIN 
      (SELECT MAX(date) AS maxdate FROM prices WHERE symbol='GOOG' AND yearweek(date) > 201001 GROUP BY yearweek(date)) 
     AS sub ON prices.date = sub.maxdate 
WHERE 
    symbol='GOOG' ; 

但年周()将仍然是一个问题,MySQL不能在这一个使用索引。预先计算此值(使用触发器),将其存储在额外列中并为此列编制索引可能会有所帮助。

0

你不能这样做吗?

SELECT * 
    FROM prices 
    WHERE symbol = 'GOOG' 
    AND date > '2010-12-18 23:59:59' 
ORDER BY date DESC 
GROUP BY yearweek(date) 
    LIMIT 1 
+0

是的。我没有想到按日期排序以获得每周的最后日期。这样可行。 – 2010-12-22 01:33:00

+0

后来我尝试了这个查询,发现它不太正确。纠正语法后,我发现它会返回每个星期一的价格。我似乎无法得到每周的最后一天使用(甚至当我将ORDER BY子句更改为ASC)。 – 2010-12-22 16:49:34

+0

嗯...有趣。也许将日期改为星期日而不是星期六。 – Stephen 2010-12-22 16:51:44

0

yearweek()禁用列日期的索引。

尝试将其更改为:

and date > date'2010-01-09' 

...其中2010-01-09是最后一天201001.周列谨防时间戳虽然。