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