Sql-Server

實際執行計劃中未使用索引視圖?

  • August 12, 2021

我有一個索引視圖的適度案例,它折疊一列並將大表中的所有條目相加:

CREATE VIEW dbo.Losses_CombinedPortfolio WITH SCHEMABINDING
AS
   SELECT [Category], [Year], 
          SUM(ISNULL(Loss,0)) AS [Loss], COUNT_BIG(*) as [Count]
   FROM dbo.Sub_Portfolio_Losses
   GROUP BY [Category], [Year]
GO
CREATE UNIQUE CLUSTERED INDEX Idx
ON dbo.Losses_CombinedPortfolio([Category], [Year]);

我最初的目標更加雄心勃勃,但索引視圖是如此的限制……我很高興能夠讓它發揮作用。

可悲的是,當我嘗試對此索引視圖進行基本查詢時:

SELECT TOP (100) * 
FROM Losses_CombinedPortfolio 
ORDER BY Loss DESC

…查詢同樣慢,實際執行計劃表明它總是返回源表並每次從頭開始計算聚合:

實際執行計劃

我只能假設這是因為我計算的“損失”列沒有實現 - 但這會讓我感到驚訝,因為聚集索引創建成功。


請注意,此視圖的主要案例是按Loss降序排序,但我無法顯式創建包含它的索引:

CREATE UNIQUE CLUSTERED INDEX Idx 
ON dbo.Losses_CombinedPortfolio
   (Category, Loss DESC, [Year]);

我得到錯誤:

無法在視圖“dbo.Losses_CombinedPortfolio”上創建索引或統計資訊“Idx”,因為鍵列“Loss”不精確、已計算且未持久化。考慮刪除對視圖索引或統計鍵中的列的引用,或者準確地更改列。如果列是在基表中計算的,請考慮將其標記為 PERSISTED 。

我嘗試通過將總損失轉換為其他類型float(甚至嘗試將其截斷為bigint)來解決“不精確”,但似乎此錯誤源於用於計算總和的基礎類型。

我很困惑 - 我看到其他問題聲稱他們能夠成功地執行聚合,例如sum在他們的索引視圖中,所以我不確定為什麼這不起作用。

您需要使用NOEXPAND查詢提示(我假設您使用的是 SQL Server 標準版),以便您的查詢使用索引視圖(而不是將其擴展到基礎表)。這將解決您的第一個問題。

這是您可以在查詢中使用它的方式:

SELECT TOP (100) * 
FROM Losses_CombinedPortfolio WITH (NOEXPAND)
ORDER BY Loss DESC

您可以在Microsoft的查詢提示文件中查看更多資訊。但這是您目前遇到的相關部分:

僅當在查詢的 SELECT 部分中直接引用視圖和 WITH (NOEXPAND) 或 WITH (NOEXPAND, INDEX( index_value

$$ ,…n $$) ) 被指定。

這是您可以使用的為數不多的查詢提示之一,而不必擔心它是不好的做法,實際上出於某些原因也建議使用它。

至於您對“不精確”錯誤的問題,這是您猜到的,因為該Loss列的類型為 FLOAT (不精確)。即使施放它也無濟於事;您必須先將基礎類型更改為精確的類型,然後才能在視圖中對其進行索引。(例如,如果您可以將數據類型更改為 DECIMAL,那麼您就可以將該列添加到您的索引中。)

文件中:

任何浮點數實數表達式都被認為是不精確的,不能作為索引的鍵;浮點數實數表達式可以在索引視圖中使用,但不能用作鍵。這也適用於計算列。任何函式、表達式或使用者定義的函式如果包含任何浮點實數表達式,則被認為是不精確的。這包括邏輯的(比較)。

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