2010-01-27 22 views
3

我使用MySQL(MyISAM數據)5.0.41和我有這個疑問:SQL計數多對多的值還是每次添加新行時都計數?

SELECT `x`.`items`.id, `x`.`items`.name, COUNT(*) AS count 
    FROM `x`.`items` INNER JOIN `x`.`user_items` 
    ON `x`.`items`.id = `x`.`user_items`.item_id 
    GROUP BY name HAVING count > 2 ORDER BY count DESC 

我有36,000用戶175,000 user_items和不斷增加60,000項。所以這個查詢是有點慢......

是更好地:

  • 有在items一個count場和更新定期(比如每次用戶將商品)
  • 或運行這樣的查詢(緩慢)..

或者是否有任何SQL將填充計數字段爲我?

感謝

+1

數據庫系統?版?你有什麼指數? – 2010-01-27 15:21:25

+0

已編輯以顯示數據庫系統和版本。 – betamax 2010-01-27 15:31:28

回答

2

您應該將user_items.item_id編入索引並對其進行分組而不是名稱。字符串的分組速度要慢得多(爲自己嘗試一下),並且索引應該加快速度。如果仍然太慢,您可以先運行GROUP BY查詢,然後加入項目表,如果您的DBMS執行計劃默認情況下沒有這樣做。

+0

我按items_id分組,它增加了大約250ms的速度。你是什​​麼意思索引'user_items.item_id'? – betamax 2010-01-27 15:45:04

+0

請查看http://dev.mysql.com/doc/refman/5.0/en/create-index.html,瞭解如何使用它。如果你可以得到你的MySQL服務器管理員應用程序,你應該可以從那裏做到。查看http://en.wikipedia.org/wiki/Index_(database)是否需要關於數據庫索引的一些信息。 – 2010-01-27 15:57:14

+0

另外,它相對於什麼增加了250ms的速度?需要多長時間,現在需要多長時間? – 2010-01-27 15:57:57

0

我的衝動將離開數據像正常形式(換句話說,不增加一個「計數」字段),然後緩存在慢速查詢結果應用級別。

如果緩存是無效的,因爲很多人都在做查詢,很少有人做兩次,然後,是的,你可以建立一個存儲過程,在一些表格會自動更新一些行。細節因數據庫供應商而異。這裏是how to do it in Postgresql。由於競爭條件,這是執行它的唯一安全方式(即在數據庫中,而不是從應用程序層中)。

+0

我認爲緩存似乎是最好的解決方案。我有點不清楚如何/何時緩存?作爲一個cron工作?一個小時或類似的東西?如果這有幫助;我正在使用Django。 – betamax 2010-01-27 15:37:01

0

您是否確實每次運行查詢時都會獲得所有36,000個用戶?如果您正在尋找性能問題的根源,那麼這可能就是它的原因。

根據您的RDBMS,您可以查看索引或物化視圖等內容。將count作爲表的一部分並試圖維護它幾乎肯定會是一個錯誤,尤其是對於數據庫的小尺寸。

3

您可以使用一箇中間的解決方案:

  • 一個ts DATETIME列添加到user_items表,將描述該用戶加入該項目的時候

  • 一個ts DATETIME列添加到users表,將描述實際的點,只要cnt,緩存的計數列

  • 定期

    INSERT 
    INTO users (id, ts, cnt) 
    SELECT * 
    FROM (
         SELECT user_id, NOW() AS nts, COUNT(*) AS ncnt 
         FROM user_items ui 
         WHERE ui.timestamp <= NOW() 
         ) 
    ON DUPLICATE KEY 
    UPDATE ts = nnow, 
         cnt = ncnt 
    
  • 無效用戶的時間戳當user_items條目被刪除

  • 發行此查詢計數項目:

    SELECT u.id, u.cnt + 
         (
         SELECT COUNT(*) 
         FROM user_items ui 
         WHERE ui.ts > u.ts 
           AND ui.user_id = u.id 
         ) 
    FROM users 
    
與新的計數和時間戳更新 users

這樣,只有新增的項目纔會被計入user_items表中, r,並且您不會經常更新記錄時遇到併發問題。

+0

結果集正在查找'items.id','items.name'和每個項目有多少用途的計數。 – 2010-01-27 16:10:51

+0

'@ NickLarsen':然後將'ts'和'cnt'列添加到'items',而不是''users',並將其放到查詢中。如果事實上,你可以做到這兩個,只是更新和無效的兩個表。 – Quassnoi 2010-01-27 16:13:15

+0

@NickLarsen沒錯。我並不是說這種方法不工作或者是錯誤的,但我認爲我的數據庫模式正在工作,這些變化可能會爲我造成不必要的問題/工作。 – betamax 2010-01-27 16:15:02

1

該查詢幾乎每次都在進行全表掃描。這是沒有辦法的。索引會加速我加速連接的速度,但隨着數據增長,查詢會變得越來越慢。

存儲摘要數據,如「計數」與「項目」將是要走的路。您可以使用存儲過程或代碼執行此操作。作爲一個雙重檢查,您可以定期(即每天一次)更新所有計數,以確保它們準確無誤。