2010-06-18 122 views
0

我有一個MySQL查詢去如下幫助優化查詢爲MySQL

SELECT 
    count(`clicks`.`user_id`) as total, 
    `users`.`fullname` 
FROM 
    `users`, 
    `clicks`, 
WHERE 
    `users`.`id` = `clicks`.`user_id` 
GROUP BY 
    `clicks`.`user_id` 
ORDER BY 
    `total` desc 
LIMIT 
    0,20; 

我在幾個按鈕,按類型遊戲運行統計數據。它有一個用戶表和一個點​​擊表。它記錄特定用戶的點擊次數。用戶可以隨時點擊按鈕。一天二十次點擊,另外三十次,等等。他們並不全是連續的。

目前約2萬用戶約180k點擊。該查詢平均運行需要1.38秒。如果可以的話,我想加快速度。

回答

1
  1. USERS.id定義爲表的主鍵?它應該是...
  2. 假設INNODB,CLICKS.user_id是否有外鍵約束將其值與USERS.id關聯?
  3. USERS.idCLICKS.user_id是數字數據類型(IE:INT),而不是基於文本?
  4. 指標應增加(如果它們不存在)爲:
    • CLICKS.user_id
    • USERS.fullname
  5. 如果存在索引,have you tried refreshes the table statistics

    ANALYZE TABLE USERS; 
    ANALYZE TABLE CLICKS; 
    
+0

爲什麼要在全名上添加索引?它不用於連接或訂單子句。 – Matt 2010-06-18 20:18:56

+0

@Matt:因爲在SELECT子句中,如果索引存在,可以觸發使用。但是,MySQL只使用每個SELECT語句的一個索引(請參閱EXPLAIN輸出)... – 2010-06-18 20:21:58

+0

'users.id'被定義爲'用戶'的主鍵。有一個單獨的「點擊」的「ID」列。這是MyISAM,不是INNODB。他們是'ints'。我無法在'clicks'上真的將索引添加到'user_id',但'fullname'上已經有索引。 – 2010-06-18 20:30:59

0

確保您已在users.idclicks.user_id上創建索引。在執行連接之前,您還可以嘗試計算點擊次數,但是我懷疑如果這實際上會提高引擎爲您執行的性能。

0

在clicks.userid上爲初學者創建索引。這將有所作爲

+0

它會有所作爲,但主要是不可能的。這是一個實時表格,並且不斷添加點擊。爲流量高的表建立索引會導致大量的服務器負載,更不要說放慢插入速度。 – 2010-06-18 20:03:13

+0

你只需要做一次,像這樣的簡單索引的插入開銷不高。 – 2010-06-18 20:32:16

1

該查詢的速度可能與獲取速度一樣快,前提條件是您有clicks.user_id和users.id索引列。

有一件事,我可以想像是負責很多緩慢,這是ORDER BY子句。看到它是一個聚合字段,它可能必須首先獲取所有數據,然後在沒有太多優化的情況下對其進行排序。任何事情都很慢時,排序是一個很好的選擇。

但是,另一個想法是維護包含總點擊次數的單獨表格。如果您需要這些記錄,那麼您最終可能不得不每次點擊運行2個查詢......一個用於現有表,另一個用於更新用戶/點擊表,該用戶/點擊表只會包含user_id和click_count以及您認爲的其他任何內容是適當的。這樣,即使有很多用戶,SELECTs也應該閃電般快,因爲你只需要檢索絕對必需的最小行數,而不是一堆,然後才能得到聚合。

+0

您無法對ORDER BY進行任何操作 - 它是唯一可靠地返回有序數據的方法。 – 2010-06-18 20:13:05

+0

@OMG Ponies:當然,但是和其他任何東西一樣,它可能會被不明智地使用,在這種情況下,必須知道它是不是罪魁禍首。如果是這樣,還有其他桌子設計可能對他的情況有意義,但除非他知道是什麼造成緩慢,否則這是一個有爭議的問題。它可能根本不是ORDER BY子句。 – Teekin 2010-07-08 17:51:42

+0

如果不指定ORDER BY子句,則無法保證訂單。但是,ORDER BY利用索引,如果它們存在... – 2010-07-08 17:56:28

0

試試這個(未經測試):

SELECT 
    C.total, 
    `users`.`fullname` 
FROM 
    `users` 
INNER JOIN 
    (SELECT COUNT(*) AS total, user_id 
    FROM 
     `clicks` 
    GROUP BY 
     `user_id` 
    ORDER BY 
     COUNT(*) 
    LIMIT 0,20) C 
ON C.user_id = users.user_id 

ORDER BY 
    C.total desc 

第一計數的行可能會節省您的時間。

+0

是的,這也是一個好主意。 – Teekin 2010-06-18 20:08:06

+0

優化器可能會將這個&OPs查詢視爲同一件事,它非常簡單。 – 2010-06-18 20:11:18

0

我只是想到了別的。使用INNER JOIN可能會獲得更好的結果。

未經測試:

SELECT 
    count(`clicks`.`user_id`) as total, 
    `users`.`fullname` 
FROM 
    `users` 
    INNER JOIN `clicks` ON `clicks`.`user_id` = `users`.`id` 
GROUP BY 
    `clicks`.`user_id` 
ORDER BY 
    `total` desc 
LIMIT 
    0,20; 
+0

使用ANSI-92語法與ANSI-89(OP列出的)沒有性能增益。 – 2010-06-18 20:11:53