2012-02-07 86 views
1

我有一個查詢:如何使這個複雜的查詢更快[MySQL]?

SELECT JL.j_id, COUNT(*) as total 
FROM j_log JL 
WHERE JL.log_time > '20120205164008' 
AND JL.j_id IN (
    SELECT j_id 
    FROM j 
    WHERE checked = '1' 
    AND expires >= '20120207164008' 
) GROUP BY JL.j_id ORDER BY total DESC LIMIT 3 

Ĵ表有很大的結構100場和裏面248986行。

下一個關鍵的存在於它

PRIMARY KEY (`j_id`), 
    KEY `expires` (`expires`), 
    KEY `checked` (`checked`), 
    KEY `checked_2` (`checked`,`expires`) 

j_log表中有大約6300萬條記錄和下一個結構

CREATE TABLE `j_log` (
    `j_id` int(11) NOT NULL DEFAULT '0', 
    `member_id` int(11) DEFAULT NULL, 
    `ip` int(10) unsigned NOT NULL DEFAULT '0', 
    `log_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 
    KEY `j_id` (`j_id`), 
    KEY `log_time` (`log_time`), 
    KEY `ip` (`ip`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 | 

所以考慮查詢都想參觀人數最多的j_id實例TOP3

這是計劃

+----+--------------------+-------+-----------------+-----------------------------------+---------+---------+------+----------+----------+----------------------------------------------+ 
| id | select_type  | table | type   | possible_keys      | key  | key_len | ref | rows  | filtered | Extra          | 
+----+--------------------+-------+-----------------+-----------------------------------+---------+---------+------+----------+----------+----------------------------------------------+ 
| 1 | PRIMARY   | JL | index   | log_time       | j_id | 4  | NULL | 63914602 |  0.36 | Using where; Using temporary; Using filesort | 
| 2 | DEPENDENT SUBQUERY | j  | unique_subquery | PRIMARY,expires,checked,checked_2 | PRIMARY | 4  | func |  1 | 100.00 | Using where         | 
+----+--------------------+-------+-----------------+-----------------------------------+---------+---------+------+----------+----------+----------------------------------------------+ 

有時它可能需要15!分鐘。

有沒有辦法讓速度更快?

回答

0
SELECT JL.j_id, COUNT(*) as total 
FROM j_log JL 
INNER JOIN j 
    ON JL.j_id = j.j_id 
    AND j.checked = '1' 
    AND j.expires >= '20120207164008' 
WHERE JL.log_time > '20120205164008' 
GROUP BY JL.j_id 
ORDER BY total 
DESC LIMIT 3 

這會更快嗎?

+0

你的'內部連接'將只拾取1行,所以總數爲1。 – Richard 2012-02-07 07:12:25

+0

不正確。每個j_id的記錄數與j_log表中具有符合日期時間約束的id的記錄數一樣多。 – 2012-02-07 15:39:09

+0

啊對不起,我改變了我的例子中表格的順序,但你是對的。 – Richard 2012-02-07 18:53:56

0
  • 爲什麼使用子查詢?
  • 爲什麼checked是一個字符串? ( '1',而不是僅僅1)
  • 爲什麼你比較jl.log_timej.expires diffrently(> VS >=

怎麼樣這個查詢

 SELECT j.j_id, COUNT(jl.j_id) as total 
     FROM j 
    LEFT JOIN j_log jl ON (jl.j_id = j.j_id AND jl.checked = '1' AND jl.log_time > '20120205164008') 
     WHERE j.expires >= '20120207164008' 

    GROUP BY j.j_id 
    ORDER BY total DESC 
     LIMIT 3 

確保j_idPRIMARY KEY兩個並在j.expires和jl.checked和jl.logtime上放置索引。 還要確保已對該字段checked進行了優化。我不確定可能的值是什麼,但我認爲它是一個布爾字段。因此,與其讓field_type BIT或使用ENUM

編輯

你也應該轉換領域j.expiresjl.log_time更好地領域。我認爲現在只是一個varchar,查看您使用的當前值:20120205164008.將其轉換爲DATETIME字段(但不要僅僅轉換表格,因爲您將丟失數據)。

+1

你不能在'j_log'表中創建'j_id'作爲PRIMARY KEY,因爲顯然有很多行具有相同的'j_id',否則爲什麼OP需要對它們進行計數? – piotrm 2012-02-07 07:28:14

+0

1.我沒有。這個查詢寫在我面前,現在我正在調查整個邏輯。所以沒有任何答案:) 2.好問題。但它可以使整個查詢變慢? 3。因爲價值是不同的:)我在想這個 – user1016265 2012-02-07 07:34:08

+0

piotrm:你是對的,我沒有注意。 j_log.j_id應該是一個索引。 user1016265:用於問題2;是的,提高速度是非常重要的。檢查該字段的字段類型是什麼... 63m記錄不是那麼多,查詢應該花費很長時間.. – Richard 2012-02-07 08:30:24