[英]SQL Server logging row visits best practice
我目前有一个文章数据库,通过增加 page_load 上的“访问次数”计数器,在一定时间内跟踪阅读次数最多的文章。 当前的“访问”计数器是articles
表中的一列(见下文):
id | title | description | visits | creation_date
---+--------+-------------+--------+-----------------
1 | test1 | test test.. | 10 | 2019-01-01
2 | test2 | test test.. | 20 | 2019-01-01
有时,我遇到了连接超时,我怀疑“访问”写入过程会出现死锁(如果并发用户一次增加同一行,则会出现数据库锁)。 我认为下面的场景是一种增强:
Articles
表中删除Visits
计数器article_visits
: article_id
和date
文章
id | title | desc | creation_date
---+-------+------+---------------
1 | test1 | desd | 2019-01-01
2 | test1 | desd | 2019-01-01
article_visits
article_id | visit_date
-----------+----------------------
1 | 2019-01-01
1 | 2019-01-01
1 | 2019-01-01
1 | 2019-01-01
1 | 2019-01-01
1 | 2019-01-01
2 | 2019-01-01
2 | 2019-01-01
2 | 2019-01-01
作为替代选项,一旦触发新的访问,我会在articles_visits
articles
上出现任何死锁。 此解决方案将使articles_visits
表快速增长,但我认为表大小不是问题。
我想知道这是否是记录文章访问的正确方法,以及优化是否是比原始解决方案更好的选择。
这是记录文章访问的好方法。 它更不容易(或根本不会)出现死锁,因为您基本上只是在追加新行。
它更灵活。 例如,您可以获得两个日期之间的访问次数。 这可以在查询时定义。 您可以存储准确的时间,因此确定视图是否有时间偏好。
缺点是查询性能。 如果您经常需要计数,那么计算可能会很昂贵。
如果这是一个问题,有多种可能的方法:
这当然是有效的,尽管您可能希望对数据库服务器需要多少额外存储和 memory 负载进行一些范围界定。
此外,我可能会为实际时间戳添加一个完整的datetime
或datetime2
列(除了当前日期列而不是代替它,因为您只想按日期进行聚合并且预先计算该值可以提高性能),也许还有其他一些列,例如 IP 地址和引荐来源。 然后,您可以将这些数据用于其他目的,例如审计、跟踪引荐来源/广告商投资回报率等。
我有兴趣了解您为什么遇到死锁。 应该是数据库平台应该能够同时处理update tablename set field = field + 1
就好了。 此处表或行将锁定然后释放,但时间不应长到足以导致死锁错误。
如果您使用跨多个表的事务更新或锁定多个表,尤其是,您可能会遇到死锁错误。 如果您以不同的顺序执行它们。
所以问题是......在您的原始代码中,您在执行更新语句时是否链接到多个表? 解决方案可能很简单,只需将更新原子化到一张表即可。
但是,我同意——你描述的表格是一个更实用的设计。
当前Articles
表不是Normalized form
。
我会说将visits
列放在Articles
表中不是De-Normalization
的正确方法。
当前Articles
表不仅给你死锁问题,而且你不能得到这么多其他类型的报告。 Daily Visit Report, Weekly Visit Report
。
创建Article_visits
表是非常好的举措。 它将非常频繁地更新。
我的Article_visits
设计
article_visit_id | article_id | visit_date | visit_count
-----------------+--------------+----------------------+----------------------
1 | 1 | 2019-01-01 | 6
2 | 2 | 2019-01-01 | 3
这里Article_Visit_id
是int identity(1,1)
,它也是Clustered Index
。
Create NonClustered Index NCI_Articleid_date ON Article_visits(article_id,visit_date)
GO
简而言之,在article_id,visit_date
上创建 CI 会很昂贵。
如果该article
在该日期不存在记录,则插入visit_count
1,如果存在则更新visit_count
,即增加 1。
Indexed View
。实际表设计,
Create Table Article(Articleid int identity(1,1) primary key
,title varchar(100) not null,Descriptions varchar(max) not null
,CreationDate Datetime2(0))
GO
Create Table Article_Visit(Article_VisitID int identity(1,1) primary key,Articleid int not null ,Visit_Date datetime2(0) not null,Visit_Count int not null)
GO
--Create Trusted FK
ALTER TABLE Article_Visit
WITH NOCHECK
ADD CONSTRAINT FK_Articleid FOREIGN KEY(Articleid)
REFERENCES Article(Articleid) NOT FOR REPLICATION;
GO
--Create NonClustered Index NCI_Articleid_Date on
-- Article_Visit(Articleid,Visit_Date)
--Go
Create NonClustered Index NCI_Articleid_Date1 on
Article_Visit(Visit_Date)include(Articleid)
Go
创建 Trusted FK 以获得 Index Seek Benefit(简而言之)。 我认为, NCI_Articleid_Date
不再需要,因为Articleid
是Trusted FK
。
Deadlock Issue
:还创建了Trusted FK
来克服死锁问题。 它通常是由于错误的Application code
或未UN-Optimized Sql query
或Bad Table Design
而发生的。除此之外还有其他一些有效原因,例如处理Race Condition
。这是 DBA 的事情。如果死锁伤害太大,那么在解决上述原因之后,你可能要Isolation Level
。
许多死锁问题是由 Sql 服务器本身自动处理的。
网上有很多关于DEADLOCK REASON的文章。
我不认为桌子大小是个问题
Table size
是个大问题。两种设计中Deadlock
的可能性都非常小。但是你总是会面临Big Size
表的其他demerit
。
我告诉你再读几篇文章。
我希望这是您具有相同数据类型的完全相同的真实表?
两个表的插入/更新频率如何?
哪个表会被更频繁地查询?
并发使用每个表。
死锁只能最小化,这样就不会出现性能问题或事务问题。
Visitorid
和Artcileid
之间有什么关系?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.