表大,影響使用
我有以下數據庫表,它將所有傳出的電子郵件保存給學生:
CREATE TABLE [dbo].[tblEmailsSent]( [id] [int] IDENTITY(1,1) NOT NULL, [Sent] [datetime] NULL, [SentByUser] [nvarchar](50) NULL, [ToEmail] [nvarchar](150) NULL, [StudentID] [int] NULL, [SubjectLine] [nvarchar](200) NULL, [MessageContent] [ntext] NULL, [ReadStatus] [bit] NULL, [Folder] [nvarchar](50) NULL, CONSTRAINT [PK_tblMessages] PRIMARY KEY CLUSTERED ( [id] ASC ) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO
該表目前儲存 18,700 條記錄。
我有很多問題,我想這可能是相關的:
- 出於某種原因,該表有 460 MB 重 - 這意味著我幾乎達到了託管包的限制。我不會想到 18,700 行會這麼重。有什麼可以做的嗎?
- 當我從表中載入前 X 行時,響應非常慢。我們談論的是一個多於 2 分鐘的執行時間(在 SSMS 中),對於如下所示的簡單查詢:
SELECT top 500 * FROM tblEmailsSent ORDER BY id desc
- 以下查詢給出零記錄,當我知道一個事實(即,我可以在表中看到)電子郵件是在 18 日當天發送時:
SELECT id FROM tblEmailsSent WHERE convert(datetime,[sent],103) = convert(datetime,'18/11/2016',103)
我正在使用 Microsoft SQL Server 2005 - 9.00.5000.00。
我正在使用
ntext
,因為我使用的是 Unicode(用於希伯來語支持)。
SET STATISTICS TIME ON
對於查詢 2,返回:(500 行受影響)。 SQL Server 執行時間: CPU 時間 = 141 毫秒,經過時間 = 112347 毫秒。
SELECT AVG(DATALENGTH(MessageContent))
查詢返回 23,363 。我將
MessageContent
列更改為nvarchar(MAX)
,然後再次執行查詢 2:SQL Server 執行時間: CPU 時間 = 47 毫秒,經過的時間 = 116726 毫秒。
……與之前只有幾秒鐘的不同。
伺服器是遠端的。它通常響應相當快,但是對於這樣一個簡單的查詢,這些結果確實非常非常慢。
使用
SET STATISTICS IO ON
回報:表'tblEmailsSent'。 掃描計數 1,邏輯讀取 17,物理讀取 0,預讀讀取 354, lob 邏輯讀取 3308,lob 物理讀取 660,lob 預讀讀取 0。 SQL Server 執行時間: CPU 時間 = 62 毫秒,經過時間 = 107245 毫秒。
社區 wiki 回答收集 Dan Guzman 和 Aaron Bertrand 評論中留下的資訊。
此表的空間需求主要取決於
MessageContent
列的大小。不推薦使用的類型的預設行為ntext
是列數據將儲存在每個 8K 的單獨 LOB 數據頁中。因此,對於 18,700 行,至少需要大約 150MB,而大於 8K 的值需要額外的頁面。
nvarchar(MAX)
如果大多數值低於 8K,則將在行中儲存較小的值並顯著減少空間需求。如果您有達到託管限制的危險,您是否考慮過另一種設計,將這些大消息儲存在文件系統上的平面文件中,並且只儲存在數據庫中的路徑?通常託管文件系統儲存比託管數據庫儲存便宜得多。
也許您的伺服器是遠端的,並且網路連接速度較慢。較長的經過時間可能是由於較低的網路頻寬和延遲。在這種情況下,您在數據庫方面無能為力。
- 嘗試重建表上的所有索引,看看是否可以回收由於碎片而產生的可用空間。如果您可以遷移到 SQL Server 2016 SP1,則可以利用壓縮。
- 您確定實際查詢需要 2 分鐘,還是 SSMS 需要 2 分鐘才能顯示結果。SSMS 中的網格是出了名的慢。在執行查詢之前,執行
SET STATISTICS TIME ON
. 執行您的查詢並在消息中查找:SQL Server Execution Times: CPU time = 0 ms, elapsed time = 0 ms.
這將是查詢的實際執行時間。 3.
select convert(datetime,'18/11/2016',103)
就時間而言,返回午夜,因此除非這些電子郵件恰好在午夜發送,否則您將不會得到匹配。如果您想查看該日期的電子郵件,請使用SELECT id FROM tblEmailsSent WHERE convert(date,[sent],103) = convert(date,'18/11/2016',103)
發布“實際”執行計劃“可能”的 xml 可為我們提供更多資訊。我認為順序 desc 不會導致任何真正的問題 -
SET IO STATISTICS ON
在執行查詢之前添加以查看您正在執行多少邏輯與物理 I/O。作為實驗要做的一件事是將選擇更改為僅檢索
ID
- 執行多長時間。添加下一列 - 執行多長時間等等。也許您的 LOB 讀取確實是減速的地方 - 如果是這種情況,我不確定您能做些什麼。從“最小列數”開始,並在每次後續執行中添加額外的列,可以提供一些關於是什麼阻礙了您的查詢的見解。另外,查看這個問答,其中有一些關於 LOB 數據的精彩討論——LOB_DATA、慢表掃描和一些 I/O 問題