2013-08-23 40 views
0

我使用MySQL表具有以下數據:如何提高大數據MYSQL查詢的性能?

users(ID, name, email, create_added) (about 10000 rows) 
points(user_id, point) (about 15000 rows) 

而且我的查詢:具有最佳點

SELECT u.*, SUM(p.point) point 
FROM users u 
LEFT JOIN points p ON p.user_id = u.ID 
WHERE u.id > 0 
GROUP BY u.id 
ORDER BY point DESC 
LIMIT 0, 10 

我只得到了前10名用戶,但隨後死亡。我該如何提高查詢的性能?

+1

對於這麼小的表索引您參加的列上應該足以使這個查詢瞬間。 – piotrm

回答

1

LEFT JOIN換成INNER JOIN會有很大幫助。確保points.pointpoints.user_id已編入索引。我假設你可以擺脫WHERE子句,因爲u.id將始終大於0(儘管MySQL在查詢優化階段可能會爲你做這件事)。

+0

MySQL只能夠使用'points'上的其中一個索引。該查詢的最佳索引可能是「ON points(user_id,point)」,這是一個覆蓋索引。 – spencer7593

2

像@Grim說的,你可以使用INNER JOIN而不是LEFT JOIN。然而,如果你真的尋求優化,我建議你在表users有一個額外的領域與預計算point。這個解決方案可以勝過當前數據庫設計的任何查詢優化。

1

這並不重要,你只能得到10行。在對數據進行排序之前,MySQL必須總結每個用戶的要點(「使用filesort」操作)。LIMIT最後應用。

覆蓋指數ON points(user_id,point)將是最佳性能的最佳選擇。 (我真的只是猜測,沒有任何EXPLAIN輸出或表定義。)

users可能是主鍵或至少一個唯一的索引。所以,很可能你已經有一個索引與id作爲前導列,或者如果它是InnoDB的主鍵簇索引)

我會忍不住來測試這樣的查詢:

SELECT u.* 
     , s.total_points 
    FROM (SELECT p.user_id 
       , SUM(p.point) AS total_points 
      FROM points p 
      WHERE p.user_id > 0 
      GROUP BY p.user_id 
      ORDER BY total_points DESC 
      LIMIT 10 
     ) s 
    JOIN user u 
    ON u.id = s.user_id 
    ORDER BY s.total_points DESC 

那請問有創建派生表的開銷,但有一個合適的索引點,包含user_id的前導列,並且包含point列,所以MySQL很可能通過使用索引來優化組,並避免使用「Using filesort」操作(對於GROUP BY)。

在結果集上可能會有一個「使用filesort」操作,以獲得按total_points排序的行。然後從中獲得前10行。

使用這10行,我們可以加入到用戶表中以獲取相應的行。

但是..這個結果有一個細微的差別,如果user_id的任何值在前10位不在用戶表中,那麼這個查詢將返回少於10行。 (我希望有一個外鍵定義,所以這不會發生,但我真的只是猜測沒有表定義。)

EXPLAIN將顯示MySQL正在使用的訪問計劃。

+0

@DRapp,良好的捕獲。感謝您修復錯誤! – spencer7593

0

有沒有想過分區? 我目前正在使用大型數據庫,併成功地改進了SQL查詢。

例如,

PARTITION BY RANGE (`ID`) (
    PARTITION p1 VALUES LESS THAN (100) ENGINE = InnoDB, 
    PARTITION p2 VALUES LESS THAN (200) ENGINE = InnoDB, 
    PARTITION p3 VALUES LESS THAN (300) ENGINE = InnoDB, 
    ... and so on.. 
) 

它使我們能夠獲得更好的速度,同時掃描MySQL表。即使表中有數百行,Mysql也將只掃描包含用戶標識1到99的分區p 1。

看看這個http://dev.mysql.com/doc/refman/5.5/en/partitioning.html