Mysql

為視圖計數創建單獨的表是一種好習慣嗎?

  • March 3, 2021

我創建了一個blog表,其中有一個名為的欄位,views_count但我聽說views_count在每個頁面視圖上更新該欄位很費力。所以我現在創建了一個單獨的視圖計數表,如下所示:

views:
id,
blog_id,
ip_address,
counter

現在我將唯一訪問儲存在views表中。當我在視圖表中保存記錄時,我也會更新blog欄位views_count欄位,這是一個好方法嗎?還是有更好的選擇?

完整創建架構:

CREATE TABLE `video_blog` (
 `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
 `category_id` int(11) UNSIGNED DEFAULT NULL,
 `title` varchar(255) NOT NULL,
 `sub_title` varchar(255) DEFAULT NULL,
 `slug` varchar(255) NOT NULL,
 `video_embed_code` text,
 `video_thumbnail` varchar(255) DEFAULT NULL,
 `video_thumbnail_alt` varchar(255) DEFAULT NULL,
 `description` text,
 `views` int(11) UNSIGNED NOT NULL,
 `is_active` tinyint(1) UNSIGNED NOT NULL DEFAULT '1',
 `created_at` datetime DEFAULT NULL,
 `updated_at` datetime DEFAULT NULL,
 PRIMARY KEY (`id`)
);

-- Table structure for table `video_blog_category`

CREATE TABLE `video_blog_category` (
 `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
 `name` varchar(255) NOT NULL,
 `description` varchar(255) DEFAULT NULL,
 `meta_title` varchar(255) DEFAULT NULL,
 `meta_description` varchar(255) DEFAULT NULL,
 `order_by` int(11) UNSIGNED DEFAULT NULL,
 `created_at` datetime DEFAULT NULL,
 `updated_at` datetime DEFAULT NULL,
 PRIMARY KEY (`id`)
);

-- Table structure for table `video_blog_views_tracker`

CREATE TABLE `video_blog_views_tracker` (
 `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
 `video_blog_id` int(11) UNSIGNED DEFAULT NULL,
 `user_ip_address` varchar(255) DEFAULT NULL,
 `counter` int(11) UNSIGNED DEFAULT NULL,
 `created_at` datetime DEFAULT NULL,
 `updated_at` datetime DEFAULT NULL,
 PRIMARY KEY (`id`)
);

**注意:**我們的網站部落格每天吸引數百萬訪問者。所以新表會經常更新。

每秒只有 10 次更新,這不是問題。

當你達到 100/sec 並且仍在使用 HDD 時,我們可以進一步討論。或 1000/秒,使用 SDD。

在更高的速率下,是的,違反教科書原則並將視圖計數器放在單獨的表中(只有count, 加上page_idPK page_id)。原因是為了避免與對主表的非計數器訪問發生衝突。

如果您在“誰查看了什麼,何時查看”的表格中跟踪每個“視圖”,那麼問題就會變得更加混亂。一方面,有INSERTs進入那個表(同樣,10/sec 不是問題)。另一方面,SELECT COUNT(*) ...會出現極端情況——數 100 是沒有問題的,但數一百萬是可以的。

“喜歡”也有類似的問題。

對於更極端的流量,您需要收集更新/插入,合併它們,然後應用它們。這可能會使您的速度再提高 10 倍,但代價是一些複雜性和更新計數器的幾秒鐘延遲。

但是,到那個時候,您將無法滿足單個伺服器的需求,您的所有問題都需要其他解決方案。分片可能是下一級設計的一部分。

對於任何從小到大的系統,您必須期望每隔一段時間進行一次重大的重新設計。對您(今天)來說,將櫃檯移出還為時過早。但是,這樣做可能會(暫時)阻止下一次重大的重新設計。

重新散列

計劃A:( 多合一)

CREATE TABLE Blog (
   id INT UNSIGNED AUTO_INCREMENT,
   lots of meta info -- title, etc
   view_ct INT UNSIGNED NOT NULL DEFAULT '0',
   PRIMARY KEY (id)
);

B計劃:( 只拆分櫃檯)

CREATE TABLE Blog (
   id INT UNSIGNED AUTO_INCREMENT,
   lots of meta info -- title, etc
   PRIMARY KEY (id)
);
CREATE TABLE BlogViews (
   blog_id INT UNSIGNED,   -- not A_I; for joining to Blog
   view_ct INT UNSIGNED NOT NULL DEFAULT '0',
   ts TIMESTAMP NOT NULL,   -- optional -- time of last viewing??
   PRIMARY KEY(blog_id)
);

方案 A 的討論:

  • 更簡單
  • 對於“低流量”網站來說已經足夠了——比如每秒 10 次瀏覽。

B的優點:

  • Needs JOIN,但僅當同時需要 meta 和 count 時。這JOIN不是一個很大的負擔。
  • 更新計數命中BlogViews,從而不會干擾任何需要元資訊的查詢,尤其是UPDATEs這樣的查詢。
  • 繁忙的網站需要 - 比如說 1000 次查看/秒的峰值載入。

何時使用 C:

  • 千次觀看/秒。
  • C 涉及收集視圖、合併它們,然後更新像 B 計劃這樣的結構。
  • Blogs這進一步將兩者與BlogViews乾擾隔離開來。
  • 查看計數可能會稍微延遲(秒)。
  • (更多細節可以在別處討論)

計劃 A2、B2、C2、D2:

  • 這些是對其他計劃的修改,您可以在其中跟踪“誰”在“何時”查看部落格。
  • SELECT COUNT(*)這不僅僅需要擔心SELECT view_ct
  • SELECT COUNT(*)如果您有一百萬次觀看,可能會很昂貴。
  • 這些擴展最好使用“匯總表”設計概念來處理,我將在此處介紹。

計劃 E(現在已經給出了實際的模式,我將其稱為 E):

video_blog_views_tracker,擺脫id,擁有

PRIMARY KEY(video_blog_id, user_ip_address)  -- should be unique

這對於計數器查詢應該是最佳的:

SELECT SUM(counter) FROM video_blog_views_tracker
   WHERE video_blog_id = ?

是的,可以video_blog.views通過一個TRIGGER或 CRON 作業將其滾動到。但在確定需要之前,我不會這樣做。

引用自:https://dba.stackexchange.com/questions/224390