Doj*_*Dev 2 mysql database-design best-practices relations
我创建了一个blog
表,其中有一个名为的字段views_count
,但我听说更新views_count
每个页面视图上的字段很麻烦。所以我现在创建了一个单独的视图计数表,如下所示:
views:
id,
blog_id,
ip_address,
counter
Run Code Online (Sandbox Code Playgroud)
现在我将独特的访问存储在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`)
);
Run Code Online (Sandbox Code Playgroud)
注意:我们的网站博客每天都有数百万访问者。所以新表会经常更新。
每秒仅 10 次更新,这不是问题。
当你达到100/秒,并且仍然使用HDD时,我们可以进一步讨论。或者使用 SDD 时为 1000/秒。
是的,在更高的速率下,违反了教科书原则,并将视图计数器放在单独的表中(只有 , count
pluspage_id
作为 PK page_id
)。原因是为了避免与主表的非计数器访问发生冲突。
如果您像“谁在何时查看什么”的表格一样跟踪每个“视图”,那么问题会变得更加混乱。一方面,INSERTs
该表中有(同样,10/秒不是问题)。另一方面,SELECT COUNT(*) ...
也会有极端——数到 100 没问题,但数到 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)
);
Run Code Online (Sandbox Code Playgroud)
Plan 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)
);
Run Code Online (Sandbox Code Playgroud)
A计划的讨论:
B的优点:
JOIN
,但仅当同时需要 meta 和 count 时才需要。这JOIN
不是一个大负担。BlogViews
,从而不会干扰任何仅需要元信息的查询,尤其UPDATEs
是此类查询。何时使用 C:
Blogs
和BlogViews
免受干扰。计划 A2、B2、C2、D2:
SELECT COUNT(*)
这不仅仅是需要担心的SELECT view_ct
。SELECT COUNT(*)
如果你有 100 万次观看,成本可能会很高。计划 E(既然已经给出了实际的模式,我将其称为 E):
为了video_blog_views_tracker
,摆脱id
,并拥有
PRIMARY KEY(video_blog_id, user_ip_address) -- should be unique
Run Code Online (Sandbox Code Playgroud)
这对于计数器查询来说应该是最佳的:
SELECT SUM(counter) FROM video_blog_views_tracker
WHERE video_blog_id = ?
Run Code Online (Sandbox Code Playgroud)
是的,可以video_blog.views
通过TRIGGER
CRON 作业将其引入。但在确定需要之前我不会这样做。
归档时间: |
|
查看次数: |
3680 次 |
最近记录: |