Sql-Server

為什麼創建索引和執行查詢比沒有它執行查詢更快?

  • December 4, 2020

我有幾百萬行的表。它包含來自外部服務的日誌,所以我決定不索引它(大量插入,稀疏讀取)。

當我執行從沒有索引的表中讀取的查詢時,它需要(不出所料)很長時間。

但是,當我創建索引並執行查詢然後刪除索引時,它會快得多(即使創建和刪除索引)。

為什麼創建臨時索引更快,而不是讓 SQL Server 來做這件事?這似乎不直覺(為什麼 SQL Server 不自己創建索引?)。這種方法有什麼缺點嗎?


有問題的查詢看起來像這樣,但我認為它不一定相關,因為我在其他地方也看到過類似的行為。

   UPDATE Device
   SET Col1 = l.Col1
       ,Col2 = l.Col2
       ,Col3 = l.Col3
   FROM dbo.Device
       OUTER APPLY (
           SELECT MAX(Id) AS [Id]
           FROM dbo.Logs 
           WHERE Logs.Device_FK = Device.Id
           GROUP BY Logs.Device_FK
       ) lastLog
       OUTER APPLY (
           SELECT Col1, Col2, FORMAT(Col3) AS "Col3"
           FROM dbo.Logs
           WHERE Logs.Id = lastLog.Id
       ) l

您的方法不一定有任何缺點,它完全取決於您寫入表的頻率與更新和讀取表的頻率,這就是為什麼 SQL Server 讓開發人員選擇索引的內容和時間,而不是試圖猜測什麼他們要。(它並不比您更了解您對特定表的未來意圖。)

我相信您了解索引是如何工作的,所以我不會詳細介紹,但一般來說,索引將數據儲存在 B-Tree 資料結構中。因此,當必須查找該索引所涵蓋的特定數據集時,它非常有效。

由於 B-Tree 的工作方式以及用於使用索引數據建構 B-Tree 的算法,通常將所有數據預先準備好然後將其索引到 B-Tree 中是最快的。當您已經有一個索引(B-Tree)並且添加或刪除了新數據時,這可能會導致額外的“洗牌”事件來重新組織 B-Tree,這可能會降低效率。(順便說一下,發生的“洗牌”讓我想到了 MergeSort 算法。這有助於我想像將所有數據放在前面與在已經排序後添加新數據的區別。)

顯然,通常情況下Tables通常不會使用完全相同的記錄保持相同的大小,這就是為什麼建議在Table前期創建索引並且 SQL Server 最好在更改時有效地更新底層 B-Tree發生在Table(並且在某種程度上它做得很好)。

但是,在某些情況下,您可能是其中之一,如果它Table具有很高的頻率INSERTsDELETEs頻率,UPDATEs並且SELECTs反對它的頻率很高,那麼在該Table臨時(就在從表中讀取之前和之後)創建和刪除索引可能會使感覺。

歸根結底,您必須測試兩種方法,看看哪種方法最適合您的環境。在選擇何時建立索引時,它的大小Table並不重要,因為如果你想在單個索引或十個記錄中儲存十億條記錄,它對 SQL Server 沒有影響,但更重要的是它取決於頻率您正在從中插入和刪除,而不是從中進行Table更新和選擇。(例如,如果您每分鐘將 100,000 條記錄插入其中,Table但每天僅從中插入SELECT一次,那麼臨時創建索引可能會更好。)

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