繁体   English   中英

SQL 服务器日志记录行访问最佳实践

[英]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

有时,我遇到了连接超时,我怀疑“访问”写入过程会出现死锁(如果并发用户一次增加同一行,则会出现数据库锁)。 我认为下面的场景是一种增强:

  1. Articles表中删除Visits计数器
  2. 创建一个包含两列的新表article_visitsarticle_iddate

文章

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 负载进行一些范围界定。

此外,我可能会为实际时间戳添加一个完整的datetimedatetime2列(除了当前日期列而不是代替它,因为您只想按日期进行聚合并且预先计算该值可以提高性能),也许还有其他一些列,例如 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_idint 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。

  1. 它是标准化的。
  2. 您可以创建任何类型的报告、当前需求+任何未来需求。
  3. 您可以显示文章明智计数。查询非常简单且高效。
  4. 您可以每周获得,甚至获得年度报告都非常容易,而且没有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不再需要,因为ArticleidTrusted FK

Deadlock Issue :还创建了Trusted FK来克服死锁问题。 它通常是由于错误的Application code或未UN-Optimized Sql queryBad Table Design而发生的。除此之外还有其他一些有效原因,例如处理Race Condition 。这是 DBA 的事情。如果死锁伤害太大,那么在解决上述原因之后,你可能要Isolation Level

许多死锁问题是由 Sql 服务器本身自动处理的。

网上有很多关于DEADLOCK REASON的文章。

我不认为桌子大小是个问题

Table size是个大问题。两种设计中Deadlock的可能性都非常小。但是你总是会面临Big Size表的其他demerit

我告诉你再读几篇文章。

我希望这是您具有相同数据类型的完全相同的真实表?

两个表的插入/更新频率如何?

哪个表会被更频繁地查询?

并发使用每个表。

死锁只能最小化,这样就不会出现性能问题或事务问题。

VisitoridArtcileid之间有什么关系?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM