Sql-Server

表大,影響使用

  • November 29, 2016

我有以下數據庫表,它將所有傳出的電子郵件保存給學生:

   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 條記錄。

我有很多問題,我想這可能是相關的:

  1. 出於某種原因,該表有 460 MB 重 - 這意味著我幾乎達到了託管包的限制。我不會想到 18,700 行會這麼重。有什麼可以做的嗎?
  2. 當我從表中載入前 X 行時,響應非常慢。我們談論的是一個多於 2 分鐘的執行時間(在 SSMS 中),對於如下所示的簡單查詢:
SELECT top 500  * 
FROM tblEmailsSent
ORDER BY id desc
  1. 以下查詢給出零記錄,當我知道一個事實(即,我可以在表中看到)電子郵件是在 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回報:

表'tblEmailsS​​ent'。
掃描計數 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,則將在行中儲存較小的值並顯著減少空間需求。

如果您有達到託管限制的危險,您是否考慮過另一種設計,將這些大消息儲存在文件系統上的平面文件中,並且只儲存在數據庫中的路徑?通常託管文件系統儲存比託管數據庫儲存便宜得多。

也許您的伺服器是遠端的,並且網路連接速度較慢。較長的經過時間可能是由於較低的網路頻寬和延遲。在這種情況下,您在數據庫方面無能為力。

  1. 嘗試重建表上的所有索引,看看是否可以回收由於碎片而產生的可用空間。如果您可以遷移到 SQL Server 2016 SP1,則可以利用壓縮。
  2. 您確定實際查詢需要 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 問題

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