2010-07-22 221 views
14

我需要一個SQL大師來幫助我加快查詢速度。從屬子查詢中的MySQL查詢花費的時間太長

我有2個表格,數量和價格。數量記錄間隔15分鐘的兩個時間戳之間的數量值。價格記錄給定時間戳的價格,對於給定的價格類型,每5分鐘有價格5記錄。

我需要2個工作時間,例如每個時期的總價格。小時或一天之間,兩個時間戳之間。這是通過每個週期(數量乘以15分鐘數量窗口中3個價格的平均值)之和來計算的。

例如,假設我想查看1天每小時的總價格。結果集中每行的總價格值是該小時內四個15分鐘期間中每一個的總價格的總和。每個15分鐘的總價格是通過將該期間的數量乘以該數量期間的3個價格(每5分鐘一個)的平均值計算出來的。

下面是我使用的查詢,並將結果:

SELECT 
MIN(`quantities`.`start_timestamp`) AS `start`, 
MAX(`quantities`.`end_timestamp`) AS `end`, 
SUM(`quantities`.`quantity` * (
    SELECT AVG(`prices`.`price`) 
    FROM `prices` 
    WHERE `prices`.`timestamp` >= `quantities`.`start_timestamp` 
    AND `prices`.`timestamp` < `quantities`.`end_timestamp` 
    AND `prices`.`type_id` = 1 
)) AS total 
FROM `quantities` 
WHERE `quantities`.`start_timestamp` >= '2010-07-01 00:00:00' 
AND `quantities`.`start_timestamp` < '2010-07-02 00:00:00' 
GROUP BY HOUR( `quantities`.`start_timestamp`); 

+---------------------+---------------------+----------+ 
| start    | end     | total | 
+---------------------+---------------------+----------+ 
| 2010-07-01 00:00:00 | 2010-07-01 01:00:00 | 0.677733 | 
| 2010-07-01 01:00:00 | 2010-07-01 02:00:00 | 0.749133 | 
| 2010-07-01 02:00:00 | 2010-07-01 03:00:00 | 0.835467 | 
| 2010-07-01 03:00:00 | 2010-07-01 04:00:00 | 0.692233 | 
| 2010-07-01 04:00:00 | 2010-07-01 05:00:00 | 0.389533 | 
| 2010-07-01 05:00:00 | 2010-07-01 06:00:00 | 0.335300 | 
| 2010-07-01 06:00:00 | 2010-07-01 07:00:00 | 1.231467 | 
| 2010-07-01 07:00:00 | 2010-07-01 08:00:00 | 0.352800 | 
| 2010-07-01 08:00:00 | 2010-07-01 09:00:00 | 1.447200 | 
| 2010-07-01 09:00:00 | 2010-07-01 10:00:00 | 0.756733 | 
| 2010-07-01 10:00:00 | 2010-07-01 11:00:00 | 0.599467 | 
| 2010-07-01 11:00:00 | 2010-07-01 12:00:00 | 1.056467 | 
| 2010-07-01 12:00:00 | 2010-07-01 13:00:00 | 1.252600 | 
| 2010-07-01 13:00:00 | 2010-07-01 14:00:00 | 1.285567 | 
| 2010-07-01 14:00:00 | 2010-07-01 15:00:00 | 0.442933 | 
| 2010-07-01 15:00:00 | 2010-07-01 16:00:00 | 0.692567 | 
| 2010-07-01 16:00:00 | 2010-07-01 17:00:00 | 1.281067 | 
| 2010-07-01 17:00:00 | 2010-07-01 18:00:00 | 0.652033 | 
| 2010-07-01 18:00:00 | 2010-07-01 19:00:00 | 1.721900 | 
| 2010-07-01 19:00:00 | 2010-07-01 20:00:00 | 1.362400 | 
| 2010-07-01 20:00:00 | 2010-07-01 21:00:00 | 1.099300 | 
| 2010-07-01 21:00:00 | 2010-07-01 22:00:00 | 0.646267 | 
| 2010-07-01 22:00:00 | 2010-07-01 23:00:00 | 0.873100 | 
| 2010-07-01 23:00:00 | 2010-07-02 00:00:00 | 0.546533 | 
+---------------------+---------------------+----------+ 
24 rows in set (5.16 sec) 

我需要的查詢比這更快的跑了很多,而且會對雖然這將是可能的。下面是從EXPLAIN EXTENDED結果...

+----+--------------------+------------+-------+-------------------+-----------------+---------+-------+-------+----------------------------------------------+ 
| id | select_type  | table  | type | possible_keys  | key    | key_len | ref | rows | Extra          | 
+----+--------------------+------------+-------+-------------------+-----------------+---------+-------+-------+----------------------------------------------+ 
| 1 | PRIMARY   | quantities | range | start_timestamp | start_timestamp | 8  | NULL | 89 | Using where; Using temporary; Using filesort | 
| 2 | DEPENDENT SUBQUERY | prices  | ref | timestamp,type_id | type_id   | 4  | const | 22930 | Using where         | 
+----+--------------------+------------+-------+-------------------+-----------------+---------+-------+-------+----------------------------------------------+ 
2 rows in set, 3 warnings (0.00 sec) 

我注意到相關子查詢不使用時間戳字段中鍵和查詢掃描行的負荷。

任何人都可以幫我把這個跑得更快嗎?

下面是創建模式,並用大量的數據填充它需要的SQL語句(2個月的價值)

# Create prices table 

CREATE TABLE `prices` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `timestamp` datetime NOT NULL, 
    `type_id` int(11) NOT NULL, 
    `price` float(8,2) NOT NULL, 
    PRIMARY KEY (`id`), 
    KEY `timestamp` (`timestamp`), 
    KEY `type_id` (`type_id`) 
) ENGINE=MyISAM; 

# Create quantities table 

CREATE TABLE `quantities` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `start_timestamp` datetime NOT NULL, 
    `end_timestamp` datetime NOT NULL, 
    `quantity` float(7,2) NOT NULL, 
    PRIMARY KEY (`id`), 
    KEY `start_timestamp` (`start_timestamp`), 
    KEY `end_timestamp` (`end_timestamp`) 
) ENGINE=MyISAM; 

# Insert first 2 rows into prices, one for each of 2 types, starting 64 days ago 

INSERT INTO `prices` (`id`, `timestamp`, `type_id`, `price`) VALUES 
(NULL, DATE_SUB(CURDATE(), INTERVAL 64 DAY), '1', RAND()), 
(NULL, DATE_SUB(CURDATE(), INTERVAL 64 DAY), '2', RAND()); 

# Fill the prices table with a record for each type, for every 5 minutes, for the next 64 days 

INSERT INTO prices (`timestamp`, `type_id`, `price`) SELECT DATE_ADD(`timestamp`, INTERVAL 32 DAY), `type_id`, RAND() FROM prices; 
INSERT INTO prices (`timestamp`, `type_id`, `price`) SELECT DATE_ADD(`timestamp`, INTERVAL 16 DAY), `type_id`, RAND() FROM prices; 
INSERT INTO prices (`timestamp`, `type_id`, `price`) SELECT DATE_ADD(`timestamp`, INTERVAL 8 DAY), `type_id`, RAND() FROM prices; 
INSERT INTO prices (`timestamp`, `type_id`, `price`) SELECT DATE_ADD(`timestamp`, INTERVAL 4 DAY), `type_id`, RAND() FROM prices; 
INSERT INTO prices (`timestamp`, `type_id`, `price`) SELECT DATE_ADD(`timestamp`, INTERVAL 2 DAY), `type_id`, RAND() FROM prices; 
INSERT INTO prices (`timestamp`, `type_id`, `price`) SELECT DATE_ADD(`timestamp`, INTERVAL 1 DAY), `type_id`, RAND() FROM prices; 
INSERT INTO prices (`timestamp`, `type_id`, `price`) SELECT DATE_ADD(`timestamp`, INTERVAL 12 HOUR), `type_id`, RAND() FROM prices; 
INSERT INTO prices (`timestamp`, `type_id`, `price`) SELECT DATE_ADD(`timestamp`, INTERVAL 6 HOUR), `type_id`, RAND() FROM prices; 
INSERT INTO prices (`timestamp`, `type_id`, `price`) SELECT DATE_ADD(`timestamp`, INTERVAL 3 HOUR), `type_id`, RAND() FROM prices; 
INSERT INTO prices (`timestamp`, `type_id`, `price`) SELECT DATE_ADD(`timestamp`, INTERVAL 90 MINUTE), `type_id`, RAND() FROM prices; 
INSERT INTO prices (`timestamp`, `type_id`, `price`) SELECT DATE_ADD(`timestamp`, INTERVAL 45 MINUTE), `type_id`, RAND() FROM prices; 
INSERT INTO prices (`timestamp`, `type_id`, `price`) SELECT DATE_ADD(`timestamp`, INTERVAL 20 MINUTE), `type_id`, RAND() FROM prices; 
INSERT INTO prices (`timestamp`, `type_id`, `price`) SELECT DATE_ADD(`timestamp`, INTERVAL 10 MINUTE), `type_id`, RAND() FROM prices; 
INSERT INTO prices (`timestamp`, `type_id`, `price`) SELECT DATE_ADD(`timestamp`, INTERVAL 5 MINUTE), `type_id`, RAND() FROM prices; 
INSERT INTO prices (`timestamp`, `type_id`, `price`) SELECT DATE_SUB(`timestamp`, INTERVAL 5 MINUTE), `type_id`, RAND() FROM prices WHERE MOD((TIME_TO_SEC(`timestamp`) - TIME_TO_SEC(CONCAT(DATE_SUB(CURDATE(), INTERVAL 64 DAY), ' 00:00:00'))), 45 *60) = 0 AND `timestamp` > CONCAT(DATE_SUB(CURDATE(), INTERVAL 64 DAY), ' 00:00:00'); 

# Insert first row into quantities, start timestamp is 64 days ago, end timestamp is start timestamp plus 15 minutes 

INSERT INTO `quantities` (`id`, `start_timestamp`, `end_timestamp`, `quantity`) VALUES (NULL, DATE_SUB(CURDATE(), INTERVAL 64 DAY), DATE_SUB(CURDATE(), INTERVAL '63 23:45' DAY_MINUTE), RAND()); 

# Fill the quantities table with a record for each 15 minute period for the next 64 days 

INSERT INTO `quantities` (`start_timestamp`, `end_timestamp`, `quantity`) SELECT DATE_ADD(`start_timestamp`, INTERVAL 32 DAY), DATE_ADD(`end_timestamp`, INTERVAL 32 DAY), RAND() FROM quantities; 
INSERT INTO `quantities` (`start_timestamp`, `end_timestamp`, `quantity`) SELECT DATE_ADD(`start_timestamp`, INTERVAL 16 DAY), DATE_ADD(`end_timestamp`, INTERVAL 16 DAY), RAND() FROM quantities; 
INSERT INTO `quantities` (`start_timestamp`, `end_timestamp`, `quantity`) SELECT DATE_ADD(`start_timestamp`, INTERVAL 8 DAY), DATE_ADD(`end_timestamp`, INTERVAL 8 DAY), RAND() FROM quantities; 
INSERT INTO `quantities` (`start_timestamp`, `end_timestamp`, `quantity`) SELECT DATE_ADD(`start_timestamp`, INTERVAL 4 DAY), DATE_ADD(`end_timestamp`, INTERVAL 4 DAY), RAND() FROM quantities; 
INSERT INTO `quantities` (`start_timestamp`, `end_timestamp`, `quantity`) SELECT DATE_ADD(`start_timestamp`, INTERVAL 2 DAY), DATE_ADD(`end_timestamp`, INTERVAL 2 DAY), RAND() FROM quantities; 
INSERT INTO `quantities` (`start_timestamp`, `end_timestamp`, `quantity`) SELECT DATE_ADD(`start_timestamp`, INTERVAL 1 DAY), DATE_ADD(`end_timestamp`, INTERVAL 1 DAY), RAND() FROM quantities; 
INSERT INTO `quantities` (`start_timestamp`, `end_timestamp`, `quantity`) SELECT DATE_ADD(`start_timestamp`, INTERVAL 12 HOUR), DATE_ADD(`end_timestamp`, INTERVAL 12 HOUR), RAND() FROM quantities; 
INSERT INTO `quantities` (`start_timestamp`, `end_timestamp`, `quantity`) SELECT DATE_ADD(`start_timestamp`, INTERVAL 6 HOUR), DATE_ADD(`end_timestamp`, INTERVAL 6 HOUR), RAND() FROM quantities; 
INSERT INTO `quantities` (`start_timestamp`, `end_timestamp`, `quantity`) SELECT DATE_ADD(`start_timestamp`, INTERVAL 3 HOUR), DATE_ADD(`end_timestamp`, INTERVAL 3 HOUR), RAND() FROM quantities; 
INSERT INTO `quantities` (`start_timestamp`, `end_timestamp`, `quantity`) SELECT DATE_ADD(`start_timestamp`, INTERVAL 90 MINUTE), DATE_ADD(`end_timestamp`, INTERVAL 90 MINUTE), RAND() FROM quantities; 
INSERT INTO `quantities` (`start_timestamp`, `end_timestamp`, `quantity`) SELECT DATE_ADD(`start_timestamp`, INTERVAL 45 MINUTE), DATE_ADD(`end_timestamp`, INTERVAL 45 MINUTE), RAND() FROM quantities; 
INSERT INTO `quantities` (`start_timestamp`, `end_timestamp`, `quantity`) SELECT DATE_ADD(`start_timestamp`, INTERVAL 15 MINUTE), DATE_ADD(`end_timestamp`, INTERVAL 15 MINUTE), RAND() FROM quantities; 
INSERT INTO quantities (`start_timestamp`, `end_timestamp`, `quantity`) SELECT DATE_SUB(`start_timestamp`, INTERVAL 15 MINUTE), DATE_SUB(`end_timestamp`, INTERVAL 15 MINUTE), RAND() FROM quantities WHERE MOD((TIME_TO_SEC(`start_timestamp`) - TIME_TO_SEC(CONCAT(DATE_SUB(CURDATE(), INTERVAL 64 DAY), ' 00:00:00'))), 45 * 60) = 0 AND `start_timestamp` > CONCAT(DATE_SUB(CURDATE(), INTERVAL 64 DAY), ' 00:00:00'); 
+5

用於DDL和示例數據的+1 – Unreason 2010-07-22 10:12:45

+0

提高性能的唯一方法是將子查詢重寫爲JOIN。 – Naktibalda 2010-07-22 10:39:49

+0

我認爲這也是JochenJung在下面推薦的內容,但是我們無法讓它產生正確的結果,並且它仍然花費相同的時間?你有什麼想法Naktibalda? – neilcrookes 2010-07-22 10:55:28

回答

5

這裏是我第一次嘗試。 這一個是髒和數據使用以下屬性:

  • 有3種5最新價格每個季度的數量(如果這是在數據違反了查詢將無法正常工作)每個
  • 通知,三個基數,這不是由數據完整性檢查保證所以因此我稱之爲髒
  • 它也是不靈活,以週期

查詢1的變化:

SELECT sql_no_cache 
    min(q.start_timestamp) as start, 
    max(q.end_timestamp) as end, 
    sum((p1.price + p2.price + p3.price)/3*q.quantity) as total 
FROM 
    quantities q join 
    prices p1 on q.start_timestamp = p1.timestamp and p1.type_id = 1 join 
    prices p2 on p2.timestamp = adddate(q.start_timestamp, interval 5 minute) and p2.type_id = 1 join 
    prices p3 on p3.timestamp = adddate(q.start_timestamp, interval 10 minute) and p3.type_id = 1 
WHERE 
    q.start_timestamp between '2010-07-01 00:00:00' and '2010-07-01 23:59:59' 
GROUP BY hour(q.start_timestamp); 

這個在我的慢測試機器上返回結果的時間爲0.01秒,原始查詢在約6秒內運行,而gnarf的查詢在約0.85秒內(所有查詢總是用SQL_NO_CACHE關鍵字進行測試,但不重複使用結果,但在一個溫暖的數據庫上)。

編輯: 這裏是一個版本,是不是在價格方面 查詢1A缺少行敏感

SELECT sql_no_cache 
    min(q.start_timestamp) as start, 
    max(q.end_timestamp) as end, 
    sum((COALESCE(p1.price,0) + COALESCE(p2.price,0) + COALESCE(p3.price,0))/( 
     3 - 
     COALESCE(p1.price-p1.price,1) - 
     COALESCE(p2.price-p2.price,1) - 
     COALESCE(p3.price-p3.price,1) 
     ) 
     *q.quantity) as total 
FROM 
    quantities q LEFT JOIN 
    prices p1 on q.start_timestamp = p1.timestamp and p1.type_id = 1 LEFT JOIN 
    prices p2 on p2.timestamp = adddate(q.start_timestamp, interval 5 minute) and p2.type_id = 1 LEFT JOIN 
    prices p3 on p3.timestamp = adddate(q.start_timestamp, interval 10 minute) and p3.type_id = 1 
WHERE 
    q.start_timestamp between '2010-07-01 00:00:00' and '2010-07-01 23:59:59' 
GROUP BY hour(q.start_timestamp); 

EDIT2: 查詢2: 這裏是一個直接的改進,不同的方法,以最小的變化查詢,帶來了execuction時候〜我的機器上0.22秒

SELECT sql_no_cache 
MIN(`quantities`.`start_timestamp`) AS `start`, 
MAX(`quantities`.`end_timestamp`) AS `end`, 
SUM(`quantities`.`quantity` * (
    SELECT AVG(`prices`.`price`) 
    FROM `prices` 
    WHERE 
    `prices`.`timestamp` >= '2010-07-01 00:00:00' 
    AND `prices`.`timestamp` < '2010-07-02 00:00:00' 
    AND `prices`.`timestamp` >= `quantities`.`start_timestamp` 
    AND `prices`.`timestamp` < `quantities`.`end_timestamp` 
    AND `prices`.`type_id` = 1 
)) AS total 
FROM `quantities` 
WHERE `quantities`.`start_timestamp` >= '2010-07-01 00:00:00' 
AND `quantities`.`start_timestamp` < '2010-07-02 00:00:00' 
GROUP BY HOUR( `quantities`.`start_timestamp`); 

即MySQL 5.1中,我想我已閱讀,在5.5這樣的THI ng(合併索引)將可用於查詢計劃程序。另外,如果你可以讓你的start_timestamp和timestamp通過外鍵相關聯,這些外鍵允許這些相關的查詢使用索引(但是爲此你需要修改設計並建立某種時間表,然後才能引用按數量和價格)。

查詢3: 最後,它做它在〜0.03秒,但最後版本應爲穩健和靈活的查詢2

SELECT sql_no_cache 
MIN(start), 
MAX(end), 
SUM(subtotal) 
FROM 
(
SELECT sql_no_cache 
q.`start_timestamp` AS `start`, 
q.`end_timestamp` AS `end`, 
AVG(p.`price` * q.`quantity`) AS `subtotal` 
FROM `quantities` q 
LEFT JOIN `prices` p ON p.timestamp >= q.start_timestamp AND 
         p.timestamp < q.end_timestamp AND 
         p.timestamp >= '2010-07-01 00:00:00' AND 
         p.`timestamp` < '2010-07-02 00:00:00' 
WHERE q.`start_timestamp` >= '2010-07-01 00:00:00' 
AND q.`start_timestamp` < '2010-07-02 00:00:00' 
AND p.type_id = 1 
GROUP BY q.`start_timestamp` 
) forced_tmp 
GROUP BY hour(start); 

注:不要忘記刪除SQL_NO_CACHE生產中的關鍵字。

在上述查詢中應用了許多反直覺技巧(有時在連接條件中重複的條件加速查詢,有時會減慢查詢速度)。對於相對簡單的查詢,Mysql是非常棒的小RDBMS,而且速度非常快,但是當複雜性增加時,很容易遇到上述情況。

所以在一般情況下,我申請了以下原則來設置關於查詢的性能我的期望:

  • 如果基本結果集< 1000行,然後查詢應該做它的業務〜0.01秒(基本結果集是功能上確定結果集的行數)

在這種特殊情況下,您從少於1000行開始(所有價格和數量在一天內,精度爲15分鐘)應該能夠計算出最終結果。

+0

你是一個傳奇,非常感謝。查詢2在0.0039秒內返回完美結果,查詢3在0.1655秒內返回完美結果 – neilcrookes 2010-07-22 14:27:45

+0

@neilcrookes,不客氣。你能否確認查詢2運行速度快於你機器上的查詢3? (最初有沒有標記的查詢1A,我現在正確地標記了,你也應該允許DB蠕蟲索引,我通常用'sql_no_cache'幾次運行查詢來進行基準測試)。 – Unreason 2010-07-22 14:33:48

+0

(不能再編輯第一條評論,因此創建一個新評論),你是一個傳奇,非常感謝。查詢1a在0.0039秒內返回完美結果,查詢2在0.1655秒內返回完美結果。查詢3遇到與@ gnarf查詢相同的問題,因爲它不返回那一小時內沒有價格並且開始和結束時間對應於那個小時內的最早和最新價格記錄的行,但返回0.0144秒。查詢1a是勝利者。再次感謝。你是一個拯救生命的人。 – neilcrookes 2010-07-22 14:48:00

0

我不知道這是否是快,但試試這個:

SELECT 
    MIN(`quantities`.`start_timestamp`) AS `start`, 
    MAX(`quantities`.`end_timestamp`) AS `end`, 
    (`quantities`.`quantity` * AVG (`prices`.`price`) * COUNT (`prices`.`price`)) AS `total` 
FROM `quantities` 
LEFT JOIN `prices` 
    ON `prices`.`timestamp` >= `quantities`.`start_timestamp` 
    AND `prices`.`timestamp` < `quantities`.`end_timestamp` 
WHERE `quantities`.`start_timestamp` >= '2010-07-01 00:00:00' 
    AND `quantities`.`start_timestamp` < '2010-07-02 00:00:00' 
    AND `prices`.`type_id` = 1 
GROUP BY HOUR( `quantities`.`start_timestamp`); 

還比較結果,因爲邏輯有點不同。

我不做SUM(quantety * AVG(價格)

我做AVG(價格)* COUNT(價格)* quantety

+0

謝謝JochenJung,但是我得到了ERROR 1111(HY000) :無效的使用組功能 – neilcrookes 2010-07-22 10:42:23

+0

我忘了一個右括號。請再試一次。 – JochenJung 2010-07-22 10:47:08

+0

我現在得到錯誤1305(42000):功能計數不存在....奇怪! – neilcrookes 2010-07-22 10:48:18

2

這應該返回相同的結果稍微快執行:

SELECT 
    MIN(`quantities`.`start_timestamp`) AS `start`, 
    MAX(`quantities`.`end_timestamp`) AS `end`, 
    SUM(`quantities`.`quantity` * `prices`.`price`) 
    * COUNT(DISTINCT `quantities`.`id`) 
/COUNT(DISTINCT `prices`.`id`) 
    AS total 
FROM `quantities` 
JOIN `prices` ON `prices`.`timestamp` >= `quantities`.`start_timestamp` 
    AND `prices`.`timestamp` < `quantities`.`end_timestamp` 
    AND `prices`.`type_id` = 1 
WHERE `quantities`.`start_timestamp` >= '2010-07-01 00:00:00' 
    AND `quantities`.`start_timestamp` < '2010-07-02 00:00:00' 
GROUP BY HOUR( `quantities`.`start_timestamp`); 

既然你無法計算AVG()SUM()裏面,我不得不做一些有趣的COUNT(DISTINCT)計算每quantities返回的prices數。我想知道如果T他給你同樣的結果與 「真實」 數據...

使用JOIN

+----+-------------+------------+-------+-------------------------------+-----------------+---------+------+-------+----------+----------------------------------------------+ 
| id | select_type | table  | type | possible_keys     | key    | key_len | ref | rows | filtered | Extra          | 
+----+-------------+------------+-------+-------------------------------+-----------------+---------+------+-------+----------+----------------------------------------------+ 
| 1 | SIMPLE  | quantities | range | start_timestamp,end_timestamp | start_timestamp | 8  | NULL | 89 | 100.00 | Using where; Using temporary; Using filesort | 
| 1 | SIMPLE  | prices  | ALL | timestamp,type_id    | NULL   | NULL | NULL | 36862 | 62.20 | Using where; Using join buffer    | 
+----+-------------+------------+-------+-------------------------------+-----------------+---------+------+-------+----------+----------------------------------------------+ 

與相同的查詢只增加LEFTJOIN

+----+-------------+------------+-------+-------------------+-----------------+---------+-------+-------+----------+----------------------------------------------+ 
| id | select_type | table  | type | possible_keys  | key    | key_len | ref | rows | filtered | Extra          | 
+----+-------------+------------+-------+-------------------+-----------------+---------+-------+-------+----------+----------------------------------------------+ 
| 1 | SIMPLE  | quantities | range | start_timestamp | start_timestamp | 8  | NULL | 89 | 100.00 | Using where; Using temporary; Using filesort | 
| 1 | SIMPLE  | prices  | ref | timestamp,type_id | type_id   | 4  | const | 22930 | 100.00 |            | 
+----+-------------+------------+-------+-------------------+-----------------+---------+-------+-------+----------+----------------------------------------------+ 

有趣的是LEFT可以完全消除end_timestamp作爲一個可能的關鍵,並改變選擇鍵這麼多,使得它採取15倍,只要...

This reference page可以幫助你多一點,如果你想看看爲你的連接指定索引提示

+0

+1這很好,還在(start_timestamp ,end_timestamp)和(type_id,timestamp)應該有所幫助。然而,我認爲我可以把它降到〜0.01秒 – Unreason 2010-07-22 11:17:29

+0

@非理性--- *劃傷頭*你說+1,但沒有人投了票;)---''---我'米感興趣的是看到你如何把它放下來! – gnarf 2010-07-22 11:27:24

+0

謝謝gnarf,這幾乎是現貨。它在我的機器上運行約0.4秒,但結果與我原來的查詢不同。我認爲的原因是因爲你除以COUNT('price'.'price'),它與GROUP子句和這個數據將是4個數量行* 3個價格行= 12,但如果你除以3,那麼它會產生與我原來的查詢結果相同。麻煩的是,我不想在查詢中硬編碼3,但我無法弄清楚SQL是如何從數據中獲得該值的。一旦這個部分被排序,它將會是完美的。任何想法非常感謝? – neilcrookes 2010-07-22 11:43:13

0

請記住,只是因爲你有你的列索引並不一定意味着他們會跑得更快。就目前而言,所創建的索引是針對每個單獨的列的,如果您僅限制一列中的數據,則會相當快地返回結果。

所以要儘量避免「使用文件排序」(你需要做的儘可能的),也許嘗試以下指標:

CREATE INDEX start_timestamp_end_timestamp_id ON quantities (start_timestamp,end_timestamp,id); 

而對於價格表(結合了3個人類似的事情索引必須爲1個指數更快的查找)

一個很好的資源這也解釋了非常詳細和如何優化索引(什麼不同解釋的意思,以及如何瞄準)是:http://hackmysql.com/case1

+0

感謝AcidRaZor,但是在價格表中添加這個索引和一個並沒有提高我的原始查詢或@gnarf建議的性能 – neilcrookes 2010-07-22 12:04:19

+0

值得一試: )但是,我仍然會通過我引用的網站也稱讚閱讀。他們詳細瞭解如何提高性能與您的查詢 – AcidRaZor 2010-07-22 12:06:32

+0

會做,謝謝 – neilcrookes 2010-07-22 12:43:23