簡體   English   中英

如何在Sql Server中構造group by的索引

[英]how to structure an index for group by in Sql Server

以下簡單查詢需要很長時間(幾分鍾)才能執行。

我有一個索引:

create index IX on [fctWMAUA] (SourceSystemKey, AsAtDateKey)
SELECT MAX([t0].[AsAtDateKey]) AS [Date], [t0].[SourceSystemKey] AS [SourceSystem]
FROM [fctWMAUA] (NOLOCK) AS [t0]
WHERE SourceSystemKey in (1,2,3,4,5,6,7,8,9)
GROUP BY [t0].[SourceSystemKey]

統計數據如下:

  • 邏輯讀取1827978
  • 物理讀取1113
  • 預讀1806459

采用完全相同的查詢並重新格式化如下給我這些統計信息:

  • 邏輯讀數36
  • 物理讀數0
  • 預讀0

執行需要31毫秒。

SELECT MAX([t0].[AsAtDateKey]) AS [Date], [t0].[SourceSystemKey] AS [SourceSystem]
 FROM [fctWMAUA] (NOLOCK) AS [t0]
 WHERE SourceSystemKey = 1
 GROUP BY [t0].[SourceSystemKey]
UNION
 SELECT MAX([t0].[AsAtDateKey]) AS [Date], [t0].[SourceSystemKey] AS [SourceSystem]
 FROM [fctWMAUA] (NOLOCK) AS [t0]
 WHERE SourceSystemKey = 2
 GROUP BY [t0].[SourceSystemKey]
UNION
 SELECT MAX([t0].[AsAtDateKey]) AS [Date], [t0].[SourceSystemKey] AS [SourceSystem]
 FROM [fctWMAUA] (NOLOCK) AS [t0]
 WHERE SourceSystemKey = 3
 GROUP BY [t0].[SourceSystemKey]
/* AND SO ON TO 9 */

如何快速制作完成該組的索引?

我發現最好的解決方案如下。 它模仿查詢的聯合版本,並且運行得非常快。

40個邏輯讀取,執行時間為3ms。

SELECT [t3].[value]
FROM [dimSourceSystem] AS [t0]
OUTER APPLY (
    SELECT MAX([t2].[value]) AS [value]
    FROM (
        SELECT [t1].[AsAtDateKey] AS [value], [t1].[SourceSystemKey]
        FROM [fctWMAUA] AS [t1]
        ) AS [t2]
    WHERE [t2].[SourceSystemKey] = ([t0].[SourceSystemKey])
    ) AS [t3]

如果不查看執行計划很難說,但是您可能想嘗試以下方法:

SELECT * FROM
(
    SELECT MAX(t0.AsAtDateKey) AS [Date], t0.SourceSystemKey AS SourceSystem
    FROM fctWMAUA (NOLOCK) AS t0
    GROUP BY t0.SourceSystemKey
)
WHERE SourceSystem in (1,2,3,4,5,6,7,8,9)

在沒有查看執行計划的情況下很難分辨,但我認為發生的事情是SQL服務器不夠聰明,無法意識到指定的WHERE子句是過濾掉組,並且對每個組包含的記錄沒有任何影響。組。 一旦SQL服務器意識到這一點就可以免費使用一些更智能的索引查找來計算出最大值(這是第二個查詢中發生的事情)

只是一個理論,但它可能值得一試。

嘗試告訴SQL Server使用索引:

...
FROM [fctWMAUA] (NOLOCK, INDEX(IX)) AS [t0]
...

確保表的統計信息是最新的:

UPDATE STATISTICS [fctWMAUA]

要獲得更好的答案,請打開兩個查詢的showplan:

SET SHOWPLAN_TEXT ON

並將結果添加到您的問題中。

您也可以在沒有GROUP BY的情況下編寫查詢。 例如,您可以使用獨有的LEFT JOIN,不包括具有較舊日期的行:

select cur.SourceSystemKey, cur.date
from fctWMAUA cur
left join fctWMAUA next
    on next.SourceSystemKey = next.SourceSystemKey
    and next.date > cur.date
where next.SourceSystemKey is null
and cur.SourceSystemKey in (1,2,3,4,5,6,7,8,9)

這可能會非常快,但我認為它不會擊敗UNION。

使用HAVING而不是WHERE,以便在發生分組后進行過濾:

SELECT MAX(AsAtDateKey) AS [Date], SourceSystemKey AS SourceSystem
FROM fctWMAUA (NOLOCK)
GROUP BY SourceSystemKey
HAVING SourceSystemKey in (1,2,3,4,5,6,7,8,9)

我也不特別關心IN子句,特別是當它可以替換為“<10”或“1到9之間”時,它們被排序索引更好地使用。

 WHERE SourceSystemKey = 3
 GROUP BY [t0].[SourceSystemKey]

您不需要按固定字段分組。

我更喜歡第一句話。 可能是我會替換的

 WHERE SourceSystemKey in (1,2,3,4,5,6,7,8,9)

喜歡的東西

 WHERE SourceSystemKey BETWEEN 1 AND 9

要么

 WHERE SourceSystemKey >= 1 AND SourceSystemKey <= 9

如果SourceSystemKey是一個整數。 但我認為這不會引起重大變化。

我將首先測試的是重建統計信息並重建表的所有索引並等待一段時間。 重建不是即時的,它將取決於服務器的繁忙程度,但這句話的結構很好,優化器使用的索引。

問候。

您是否嘗試在SourceSystemKey列上創建另一個索引? 在where子句中使用該列時,大量的邏輯讀取使我認為它正在進行索引/表掃描。 你可以在這個上運行執行計划,看看是否是這種情況? 執行計划也可能提出索引建議。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM