簡體   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