2012-04-11 28 views
1

我試圖運行我認爲是一個相當大的數據集上的簡單查詢,它需要很長時間才能執行 - 它停止在「發送數據」狀態3 -4小時以上。MySQL永遠在「發送數據」。簡單的查詢,大量的數據

表看起來是這樣的:

CREATE TABLE `transaction` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, 
`uuid` varchar(36) NOT NULL, 
`userId` varchar(64) NOT NULL, 
`protocol` int(11) NOT NULL, 
... A few other fields: ints and small varchars 
`created` datetime NOT NULL, 
PRIMARY KEY (`id`), 
KEY `uuid` (`uuid`), 
KEY `userId` (`userId`), 
KEY `protocol` (`protocol`), 
KEY `created` (`created`) 
) ENGINE=InnoDB AUTO_INCREMENT=61 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4 COMMENT='Transaction audit table' 

和查詢是在這裏:

select protocol, count(distinct userId) as count from transaction 
where created > '2012-01-15 23:59:59' and created <= '2012-02-14 23:59:59' 
group by protocol; 

表有大約2.22億行,並在查詢的WHERE子句過濾下降到約20百萬行。不同的選項會將其降至大約700,000個不同的行,然後在分組後(以及查詢最終完成時),實際返回4到5行。

我意識到這是很多的數據,但似乎4-5小時是這個查詢非常長的時間。

謝謝。

編輯:作爲參考,它在AWS上運行在db.m2.4xlarge RDS數據庫實例上。

回答

3

這是一個非常重的查詢。要理解爲什麼需要這麼長時間,你應該瞭解細節。

在索引字段中有一個範圍條件,即MySQL在索引中找到最小的創建值,並且每個值都從索引獲取相應的主鍵,從磁盤檢索該行並獲取必需的字段(protocol,userId)在當前索引記錄中丟失,將它們放在一個「臨時表」中,對這些700000行進行分組。該索引實際上可以使用,僅用於加快範圍條件。

加速它的唯一方法是有一個包含所有必要數據的索引,這樣MySQL就不需要對行的磁盤查找進行操作。這就是所謂的covering index。但是您應該明白,索引將駐留在內存中,並且將包含〜sizeOf(created+protocol+userId+PK)*rowCount個字節,這可能會成爲更新表和其他索引的查詢本身的負擔。創建單獨的聚合表並使用查詢定期更新表更容易。

+0

+1。添加另一個帶有「created」列的索引會使OP索引在「created」列冗餘;只有'created'列的索引可以被刪除。有可能一個不同的覆蓋索引,'協議'和'創建'列交換,也可能會提高性能。在這種情況下,只有'protocol'列的單獨索引是多餘的。 – spencer7593 2014-02-14 23:10:09

1

不同的和不同的將需要排序和存儲服務器上的臨時數據。有了那麼多的數據可能需要一段時間。

對userId,創建的和協議的不同組合進行索引將有所幫助,但我不能說多少或哪些索引對大多數人有幫助。

+0

'覆蓋索引'將有助於(這個特定查詢的執行)最多。權衡是維持指數所需的資源。 – spencer7593 2014-02-14 23:07:21

11

爲什麼不分析查詢並查看究竟發生了什麼?

SET PROFILING = 1; 
SET profiling_history_size = 0; 
SET profiling_history_size = 15; 
/* Your query should be here */ 
SHOW PROFILES; 
SELECT state, ROUND(SUM(duration),5) AS `duration (summed) in sec` FROM information_schema.profiling WHERE query_id = 3 GROUP BY state ORDER BY `duration (summed) in sec` DESC; 
SET PROFILING = 0; 
EXPLAIN /* Your query again should appear here */; 

我認爲這將有助於你在看哪兒查詢需要一定的時間,並根據結果可以執行優化操作。