2009-02-08 83 views
5

我想開始計算瀏覽網頁的次數,因此需要某種簡單的計數器。什麼是最好的可擴展的方法呢?什麼是在MySQL中實現計數器字段的最佳方式

假設我有,每一行對應一個頁表Frobs - 一些明顯的選項是:

  1. 在Frobs表,得到 使用UPDATE Frobs SET NumViews = NumViews + 1每個視圖時更新有一個unsigned int NumViews場 。簡單但不是很好,因爲我瞭解它。

  2. 有一個單獨的表FrobViews 其中爲每個視圖插入一個新行。要顯示 的視圖數量,則需要執行一個簡單的SELECT COUNT(*) AS NumViews FROM FrobViews WHERE FrobId = '%d' GROUP BY FrobId。這不涉及任何更新,因此可以避免MyISAM表中的表鎖定 - 但是,如果要顯示每個頁面上的視圖數,讀取性能將受到影響。

你是如何做到的?

這裏有一些很好的建議: http://www.mysqlperformanceblog.com/2007/07/01/implementing-efficient-counters-with-mysql/ 但我希望聽到SO社區的意見。

我目前使用InnoDb,但對InnoDb和MyISAM的答案感興趣。

回答

2

我會採取第二種方法,並將數據從常規基礎上的第一個解決方案彙總到表中。這樣你就可以獲得兩種解決方案的優點。更清晰: 在每次擊中時,您都會在表中插入一行(讓它命名爲hit_counters)。這張表只有一個字段(pageid)。每運行一個腳本(通過cronjob),它會聚合hit_counters表中的數據,並將其放到第二個表中(讓它命名爲'hit'),其中有兩個字段:pageid和總點擊數

林不知道,但恕我直言,沒有InnoDB的不是幫助你非常多的解決方案1,如果你在同一頁上的許多命中:Innodb的鎖定該行同時更新,因此所有其他更新此行將會推遲

根據。什麼是你寫的程序也可以通過計算你的應用程序和更新數據庫來每隔x秒更新一次,這隻有在你使用持久存儲的程序設計語言(比如Java Servlets而不是PHP)時纔有效

3

如果可擴展性對您而言比數據的絕對準確性更重要,那麼您可以在短時間內緩存應用程序中的查看計數,而不是在每個頁面視圖上都訪問數據庫 - 例如,每100次查看只更新一次數據庫。

如果您的應用程序在數據庫更新之間崩潰,那麼顯然您會丟失一些數據,但是如果您可以容忍一定數量的不準確性,那麼這可能是一種有用的方法。

0

我做了什麼,它可能不適用於您的場景,是在存儲過程中準備/返回頁面上顯示的數據,我在使表格計數器更新的同時返回數據 - 這樣,只有一個調用服務器的服務器都能獲取數據,並在同一個調用中更新計數器。

如果您不使用SP的話(或者如果頁面上沒有數據庫數據),您可能無法使用此選項,但如果您有此選項,則需要考慮。

3

插入到數據庫中並不是您想在頁面瀏覽中執行的操作。由於MySQL上的複製是單線程的,因此使用所有插入更新從屬數據庫可能會遇到問題。

在我的公司,我們每天服務25M頁面,我們採取了分層的方法。

視圖計數器存儲在一個帶有2列(profileId,viewCounter)的單獨表中,它們都是無符號整數。

對於不經常查看的項目,我們更新頁面視圖上的表格。 對於經常查看的項目,我們會在1/10左右更新MySQL。對於這兩種類型,我們都會在每次點擊時更新Memcache。
int Memcache::increment (string $key [, int $value = 1 ])

if (pageViews < 10000) { UPDATE page_view SET viewCounter=viewCounter+1 WHERE profileId = :? }

else if ((int)rand(10) == 1) { //UPDATE page_view SET viewCounter= ?:cache_value WHERE profileId = :? }

做COUNT(*)是InnoDB的效率非常低(的MyISAM保持計數在索引統計信息),但是一個MyISAM將鎖表上讀降低併發性。對50,000或100,000行進行count()將花費很長時間。在PK上做選擇會非常快。

如果你需要更多的擴展性,你可能想看看redis

相關問題