Sql-Server

將不同表中的數據匯總到一個表中是不好的做法嗎?

  • August 18, 2015

背景

我為一個大型健康記錄數據庫(寫 SP、函式、作業等)編寫了很多大型報告並通常維護它。原始模式和使用它的軟體來自不同的供應商,因此我無法在結構上對其進行太多更改。有許多記錄需要跟踪,例如實驗室、程序、疫苗等,它們分散在幾十張表中,其中許多表臃腫且索引不佳(我已經能夠在一定程度上解決這個問題)。

問題

問題是因為我們對數據庫幾乎沒有控制權,而且它可以從任何給定的更新或更新檔中改變,這使得編寫和維護這些報告變得困難和乏味——尤其是當有大量重疊時。只需要一個更新檔,我就被困在重寫一打報告的大部分內容中。此外,隨著連接、嵌套選擇和應用的堆積,查詢很快就會變得模糊和緩慢。

我的“解決方案”

我的計劃是將所有這些記錄寫入一個“包羅萬象”的表,並在原始表上寫入觸發器以維護此聚合表中的記錄。當然,我需要確保我的觸發器在更新後完好無損,但從可維護性的角度來看,這會容易得多,並且只是引用數據。

該表將又薄又長,僅儲存所需的數據,如下所示:

CREATE TABLE dbo.HCM_Event_Log (
   id INT IDENTITY,
   type_id INT NULL,
   orig_id VARCHAR(36) NULL,
   patient_id UNIQUEIDENTIFIER NOT NULL,
   visit_id UNIQUEIDENTIFIER NULL,
   lookup_id VARCHAR(50) NULL,
   status VARCHAR(15) NULL,
   ordered_datetime DATETIME NULL,
   completed_datetime DATETIME NULL,
   CONSTRAINT PK_HCM_Event_Log PRIMARY KEY CLUSTERED (id)
)

然後我會為 type_id 和 item 分組等內容創建各種關係表。

我開始懷疑這個想法,因為其中幾個表被寫入了相當多的內容,我要編寫的 SP 和報告也會大量引用這些數據。所以我擔心這張表會成為一個記錄鎖定和性能的噩夢,有這麼多的 I/O。

我的問題

是壞主意還是好主意?我意識到 SQL Server(2008 r2 標準版 BTW)和“有時”規則中的每種情況都不同,但我真的只是在尋找一般建議。

我開始考慮使用服務代理,但我只會執行簡單的更新/插入(請參閱已接受答案的替代方案)。在許多情況下,數據需要是實時的,因此使用備份數據庫實際上是行不通的。性能對我們來說已經是一個問題,但其中大部分與硬體相關,很快就會得到解決。

如果我理解正確的話,

  • 你有一個大型的第三方系統,
  • 你沒有太多的控制權,
  • 您製作複雜的報告,直接從該第三方數據庫讀取數據,
  • 您的查詢取決於第三方數據庫的內部結構。

我會這樣處理它:

  • 建立我自己的獨立數據庫,我可以完全控制它。
  • 設置一個同步程序,從第三方數據庫的相關表和列中讀取數據,並將數據插入/更新到我的數據庫中。
  • 基於我的數據庫的穩定結構開發我的複雜報表。

在這種情況下,您可以微調數據庫的結構和索引以提高報告的性能,而不會影響第三方系統。除非原始資料結構發生巨大變化,否則如果第三方數據庫發生變化,您對報表的查詢邏輯不會發生變化。您只需要調整同步過程。

同步過程實際上就是轉換過程——您將第三方數據庫中的數據轉換為您需要的結構。此轉換過程的一部分可能是修復原始第三方數據庫可能存在的任何規範化問題。只有系統的這一部分需要了解和依賴第三方系統的內部結構。您的主要報告和主要查詢將僅取決於您的數據庫。

因此,重點是 - 分離並限制系統中依賴於第三方系統內部的部分。

更新

關於實時性要求。順便說一句,我一直認為“實時”的定義是“保證響應時間”,而不是“一些小的響應時間”。當然,這取決於您的應用程序。在我的實踐中,如果我在檢測到更改的一分鐘內同步兩個數據庫就足夠了。如果使用者在螢幕上看到報告並且某些基礎數據發生更改,則必須以某種方式重新執行報告以反映此更改。您可以輪詢更改或收聽某些事件/消息,但仍必須再次執行報告查詢以顯示最新更改。

您已經打算編寫觸發器來擷取原始表中的更改並將這些更改寫入一個通用表。因此,按照您的意圖擷取更改,但將它們寫入正確規範化的表,而不是單個表。

因此,這是一種極端情況——第三方資料結構到您的內部資料結構的轉換是在觸發INSERT/UPDATE/DELETE第三方表的觸發器中執行的。這可能很棘手。觸發器程式碼將取決於兩個系統的內部結構。如果轉換是非平凡的,它可能會延遲原始INSERT/UPDATE/DELETE到他們失敗的點。如果您的觸發器中存在錯誤,則可能會影響原始事務直至其失敗。如果第三方系統發生變化,可能會破壞您的觸發器,從而導致第三方系統的交易失敗。

不太極端的情況。為了使觸發器的程式碼更簡單且不易出錯,將所有擷取的更改寫入一些暫存/審計/差異表,設置一些標誌/發送一條消息,表明有更改未決,並啟動將要進行的主要轉換過程通過這些中間表並執行轉換。這裡主要的是,潛在的繁重轉換過程應該發生在原始事務的範圍之外。

乍一看,它看起來很像您在問題中的原始建議。但是,不同之處在於:capture-all 表只是臨時保存數據;數據量很小——只是發生了變化;它不必是一個表;最終數據將儲存在單獨的適當規範化的永久表中,您可以完全控制這些表,這些表獨立於第三方系統,並且您可以針對查詢進行調整。

務必將其放入一組標準化的表格中,以便您可以調整導入階段,而不必更改複雜的報告和查詢。但數據仍應進行規範化,這將需要多個表(但具有良好的索引)。

正如其他人提到的,不要使用觸發器,批量同步。

不要擔心大量的連接,當數據被規範化和正確索引時,這些不會增加任何顯著的成本或管理負擔。

當您需要能夠對無法預測的數據進行大量不同類型的查詢時,是時候將其非規範化為數據倉庫之類的東西了。它有自己的缺點和成本,應該在適當的地方使用,而不是作為首選。

引用自:https://dba.stackexchange.com/questions/110993