2011-08-19 142 views
0

我有兩個MySQL表與後續的結構:如何優化此查詢?

mysql> describe symbol; 
+-------------+--------------+------+-----+---------+----------------+ 
| Field  | Type   | Null | Key | Default | Extra   | 
+-------------+--------------+------+-----+---------+----------------+ 
| id   | int(11)  | NO | PRI | NULL | auto_increment | 
| symbol  | varchar(250) | NO |  | NULL |    | 
+-------------+--------------+------+-----+---------+----------------+ 
2 rows in set (0.00 sec) 

mysql> describe price; 
+-----------+---------+------+-----+---------+----------------+ 
| Field  | Type | Null | Key | Default | Extra   | 
+-----------+---------+------+-----+---------+----------------+ 
| id  | int(11) | NO | PRI | NULL | auto_increment | 
| id_symbol | int(11) | NO | MUL | NULL |    | 
| date  | date | NO | MUL | NULL |    | 
| price  | double | NO |  | NULL |    | 
+-----------+---------+------+-----+---------+----------------+ 
4 rows in set (0.00 sec) 

我要查詢價格表來獲得與兩個符號N個價格清單(對它們進行比較)

這是一個樣品結果:

DATE  SYMBOL 1 SYMBOL 2 
2011-01-01 100  23 
2011-01-02 92  26 
2011-01-03 89  50 

所以我需要找到兩個相同的數據並返回他們的價格。 我已經創建了一個看起來可以完成這項工作的查詢,但可能並不是非常優化。

SELECT * 
FROM price AS a 
    JOIN price AS b ON a.date = b.date 
WHERE a.id_symbol = 1 AND b.id_symbol = 2 
ORDER BY a.date DESC 
LIMIT 100 

您怎麼看?

我可以優化查詢做些什麼(或者可以改變表結構)嗎?

編輯:

這是EXPLAIN {查詢}的

mysql> EXPLAIN SELECT * 
    -> FROM price AS a 
    -> JOIN price AS b ON a.date = b.date 
    -> WHERE a.id_symbol = 1 AND b.id_symbol = 2 
    -> ORDER BY a.date DESC 
    -> LIMIT 100; 
+----+-------------+-------+------+----------------+-----------+---------+-------+------+-----------------------------+ 
| id | select_type | table | type | possible_keys | key  | key_len | ref | rows | Extra      | 
+----+-------------+-------+------+----------------+-----------+---------+-------+------+-----------------------------+ 
| 1 | SIMPLE  | a  | ref | date,id_symbol | id_symbol | 4  | const | 921 | Using where; Using filesort | 
| 1 | SIMPLE  | b  | ref | date,id_symbol | id_symbol | 4  | const | 966 | Using where     | 
+----+-------------+-------+------+----------------+-----------+---------+-------+------+-----------------------------+ 
2 rows in set (0.03 sec) 

你認爲什麼結果呢?

然後......什麼是解釋「行」列中的921和966?如果我數 價格我有符號1和符號2我得到:912和912: - | 是什麼?

(PS是的,我的錯誤,我不得不改變*與我想要的列)

+2

「不是非常優化」?有什麼問題? – Vache

+0

您的查詢是否緩慢? – Ibu

+0

你不想指定不使用'select *'的列嗎? – Rup

回答

0

撇開關於過早優化也許是非常合適的意見,你嘗試過使用EXPLAIN(http://dev.mysql.com/doc/refman/5.1/en/using-explain.html)怎麼看你的查詢實際執行?從那裏你可能想看看添加索引。

+0

我不相信這是一個答案。 –

+0

我已經添加了EXPLAIN結果,請看上面。 – Dail

1

根據有限的信息,關於您所能做的只是在id_symbol ASC, date DESC上創建一個索引,並可能會將*限制爲僅需要的列。

您最大的「加速」可能是將您的兩個查詢合併爲一個查詢,然後運行該查詢並解析結果集,而不是運行一個查詢來獲取所有符號對,然後查詢另一個查詢每個符號對。您不提供原始查詢,因此無法建議此組合查詢。

1

這是你的原始查詢

SELECT * 
FROM price AS a 
JOIN price AS b ON a.date = b.date 
WHERE a.id_symbol = 1 AND b.id_symbol = 2 
ORDER BY a.date DESC 
LIMIT 100; 

您需要進行兩個重大變化:

CHANGE#1:重構您的查詢

只使用密鑰,使何在,ORDER BYS首先發生,JOINs last

SELECT A.date,GROUP_CONCAT(A.price ORDER BY A.id_symbol) prices 
FROM price A 
INNER JOIN 
(
    SELECT BB.* FROM 
    (
    SELECT DISTINCT date FROM 
    (
     SELECT AAAA.date FROM 
     (SELECT date FROM price WHERE id_symbol = 1) AAAA 
     INNER JOIN 
     (SELECT date FROM price WHERE id_symbol = 2) BBBB 
     USING (date) 
     ORDER BY AAAA.date 
    ) AAA ORDER BY date DESC LIMIT 100 
) AA 
    INNER JOIN 
    (SELECT date,id_symbol FROM price WHERE id_symbol in (1,2)) BB 
    USING (date) 
    ORDER BY BB.date DESC,BB.id_symbol 
) B 
USING (date,id_symbol) GROUP BY date; 

CHANGE#2:CREATE INDEX支持重構QUERY

ALTER TABLE price ADD INDEX symbol_date_id_ndx (id_symbol,date,id); 
ALTER TABLE price ADD INDEX date_id_ndx (date,symbol_id); 

試試看!

+0

羅蘭多非常感謝你的回答。只有一件事,爲什麼你爲symbol_date_id_ndx添加「id」?id_symbol和date是有用的,那麼「id」是什麼? – Dail

+0

將所有必要的字段放在索引中,使MySQL查詢優化器僅從索引獲取所需的數據。這被稱爲索引掃描。這來自被稱爲覆蓋索引的概念:請參閱http://peter-zaitsev.livejournal.com/6949.html,http://www.mysqlperformanceblog.com/2006/11/23/covering-index-and-prefix -indexes /和http://ronaldbradford.com/blog/tag/covering-index/獲取關於何時,如何以及爲什麼創建或不創建覆蓋索引的更多信息。 – RolandoMySQLDBA

+0

羅蘭多,我必須刪除以前創建的索引(id_symbol,date)嗎?謝謝 – Dail