Sql-Server

SQL Server 2008 中的 varchar 儲存和比較

  • November 30, 2015

我有一個類似這樣結構的大表:

Id       bigint primary key
Sequence int
Parent   int foreign key
Data1    varchar(20)
Data2    varchar(20)
Data3    varchar(20)
Data4    varchar(20)
Data5    varchar(20)

數據 1-5 是文本欄位(主要是數字和破折號),可用於幫助防止意外記錄重複,但數據實際上偶爾會重複。我們必須讓使用者確認是的,沒關係,它是重複的。

對於數百萬行,這種重複檢查可能很耗時。我的任務是確保我們能夠處理我們保存在這個數據庫中的數據量的三倍。以前的開發人員告訴我,目前的過程不適用於那麼多數據(當然,數據比我在這裡包含的要多得多,儘管查找重複項的實際查詢非常簡單系統的這一部分顯然對額外的延遲很敏感)。我自己沒有做過實驗來證明這一點,但我相信他們的判斷,無論如何我都想盡可能地減少影響。不幸的是,直到過程的後期,我才能進行大量的測試。

所有 5 個欄位必須匹配才能算作重複。我懷疑這永遠不會改變,但有人告訴我,在可預見的未來,所有 5 必須完全匹配。我在想,通過添加一個作為組合值雜湊的索引列,我將能夠更快地找到潛在的重複項。不過,我仍然需要比較各個值來解決雜湊衝突。我也會通過組合這些值本身來獲得什麼嗎?那麼一個雜湊列和一個在分隔字元串中包含所有 5 個值的單列,我用來比較而不是分別比較每個值?

如果 varchars 不與行的其餘部分一起儲存,我似乎只會受益,我一直認為它們是。然而,情況似乎並非如此。我很難找到具體資訊,但似乎如果我的行小於 8060 字節,則將在行中分配完整的 20 個字元。只有當行超過 8060 時,才會選擇一些 varchar 列移動到單獨的頁面中。

任何解釋如何儲存小 varchars 的文件,以及關於是否將列組合成單個列是否會對性能產生影響的任何建議都將不勝感激。

編輯:該表將有數百萬行(估計為 1000 萬行)。每行的最大長度肯定會小於 8060 字節,儘管我現在不能給你一個確切的數字。

添加一個包含CHECKSUM5 個欄位的持久計算欄位,並使用它來執行比較。

對於特定的欄位組合,該CHECKSUM欄位將是唯一的,並且儲存為一個INT更容易在WHERE子句中進行比較的目標。

USE tempdb; /* create this in tempdb since it is just a demo */

CREATE TABLE dbo.t1
(
   Id       bigint constraint PK_t1 primary key clustered identity(1,1)
   , Sequence int
   , Parent   int not null constraint df_T1_Parent DEFAULT ((0))
   , Data1    varchar(20)
   , Data2    varchar(20)
   , Data3    varchar(20)
   , Data4    varchar(20)
   , Data5    varchar(20)
   , CK AS CHECKSUM(Data1, Data2, Data3, Data4, Data5) PERSISTED
);

GO

INSERT INTO dbo.t1 (Sequence, Parent, Data1, Data2, Data3, Data4, Data5)
VALUES (1,1,'test','test2','test3','test4','test5');

SELECT *
FROM dbo.t1;
GO

在此處輸入圖像描述

/* this row will NOT get inserted since it already exists in dbo.t1 */
INSERT INTO dbo.t1 (Sequence, Parent, Data1, Data2, Data3, Data4, Data5)
SELECT 2, 3, 'test', 'test2', 'test3', 'test4', 'test5'
WHERE Checksum('test','test2','test3','test4','test5') NOT IN (SELECT CK FROM t1);

/* still only shows the original row, since the checksum for the row already
exists in dbo.t1 */
SELECT *
FROM dbo.t1;

為了支持大量行,您需要在該CK欄位上創建一個 NON-UNIQUE 索引。

順便說一句,您忽略了在此表中提及您期望的行數;這些資訊將有助於提出很好的建議。

行內數據限制為最大 8060字節,這是單頁數據的大小,減去每頁所需的成本。任何大於該值的單行都會導致行數據的一些頁外儲存。我確信http://dba.stackexchange.com的其他貢獻者可以為您提供關於儲存大行的引擎內部的更簡潔的定義。目前你最大的一排有多大?

如果其中的項目Data1, Data2, Data3...具有以不同順序出現的相同值,則校驗和將不同,因此您可能需要考慮這一點。

在與The Heap上出色的Mark Storey-Smith進行了簡短討論之後,我想提供一個類似的,儘管可能更好的選擇來計算相關欄位的雜湊值。您可以交替使用計算列中的函式。 有一些陷阱,例如必須將欄位連接在一起,包括欄位值之間的某種類型的分隔符,以便傳遞單個值。有關 的更多資訊,馬克推薦了這個網站。顯然,MSDN 在http://msdn.microsoft.com/en-us/library/ms174415.aspx也有一些很棒的資訊HASHBYTES()``HASHBYTES()``HASHBYTES()``HASHBYTES()

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