2013-10-28 53 views
2

約束

由於該應用程序是動態構建的,因此我無法在此時更改查詢,並且我們無法在今天,本週甚至本月將代碼推送到PROD。這必須在數據庫中解決。這就是我評估索引的原因。查詢性能,索引和預測覆蓋索引的寫入時間性能命中?

我們在我們的數據庫中有一個表,CaseHistory,它有〜10MM行。不可怕,但它是一個成長的痛苦。讀取時間開始對從搜索幹這樣的查詢苦:現在

select CaseNumber 
    ,isnull(
     (
      select convert(varchar,min(CreationTimeGMT),101) 
      from CaseHistory 
      where CaseNumber = c.CaseNumber 
       and ActionTypeID = 1 
     ), 'N/A' 
    ) as CreationTimeGMT 
    ... 
from [Case] c 
where CaseNumber in (
    select CaseNumber from CaseHistory 
    where ActionTypeID <> 1 and 
     CreationTimeGMT >= '10/25/2013' 
    ) AND 
    CaseNumber in (
     select CaseNumber from CaseHistory 
     where ActionTypeID <> 1 and 
      CreationTimeGMT <= '10/25/2013' 
    ) 

,乍看之下可能會覺得子查詢搶CreateionTimeGMT可能是一個問題,但我不相信是因爲我分析了執行計劃。該查詢的執行計劃使用SEEK上的處理中的99%處理IX_CaseHistory_1(如下面的當前索引所示)。爲了進一步具體的原因我不相信它是子查詢,直接搜索針對CaseNumber,像這樣:

select CaseNumber 
    ,isnull(
     (
      select convert(varchar,min(CreationTimeGMT),101) 
      from CaseHistory 
      where CaseNumber = c.CaseNumber 
       and ActionTypeID = 1 
     ), 'N/A' 
    ) as CreationTimeGMT 
    ... 
from [Case] c 
where CaseNumber = '123456' 

1s而上述查詢13s15s之間運行。

當前指數

IX_CaseHistory (CaseNumber (ASC)) 
IX_CaseHistory_1 (ActionTypeID (ASC)) 
IX_CaseHistory_2 (CreationTimeGMT (ASC)) 

所以,我想要做的是CaseNumber, ActionTypeID, CreationTimeGMT建立聚集覆蓋索引。目前集羣索引在IDENTITY PK

爲什麼要羣集?

因爲我想這個查詢的運行速度太(這是執行1000年代每日次):

select CaseHistoryID 
    ,CaseNumber 
    ,ActionTypeID 
    ,CreationTimeGMT 
    ,UserID 
    ,Notes 
from CaseHistory 
where CaseNumber = @CaseNumber 
order by CreationTimeGMT 

不過,我有一個基本的關注,我怎麼能預測什麼樣的命中這將有寫時間?

+1

+1的整潔問題 – SriniV

+0

能否請您添加相關的DB標籤? – SriniV

+2

我們需要查看查詢計劃以評估您的分析。 – Jodrell

回答

1

我該如何預測這會對寫入時間產生怎樣的影響?

對於插入(我假定這就是你的「寫」的意思),具有聚簇索引工作時,主要關注的是其中將新的數據插入。如果您通常將值添加到聚簇索引的末尾(例如,自動遞增鍵),則寫入應該非常快 - 它只是將新記錄添加到末尾。

就你而言,我假設插入的是而不是連續的,但是被隨機放置在現有的數據中。在這種情況下,您需要考慮fill factor,這將確定現有記錄之間將保留多少空間以接受插入。

由於結果數據可能分佈在多個頁面上,所以需要更多的I/O,因此允許許多插入的低填充因子的取捨是非索引列的更高讀取時間。還需要更多的磁盤空間,因爲表需要爲新插入分配空的空間(而不是僅僅自動增長)

我會將填充因子減少到80(意思是留出20%的新插入空間)和定期重組您的表格以在新數據的記錄之間留出一定空間。

+0

是的,通過*寫*您是正確的,我的意思是'INSERT'。所以,如果我離開了'IDENTITY'列上的* current * **聚簇索引**,並添加了新覆蓋的索引,那麼我真的不會看到寫入次數增加了嗎?在編寫期間重建新覆蓋索引的開銷是否不足以擔心? –

+0

你只能有一個聚集索引,所以你必須_replace_當前的聚集索引。 –

+0

我明白了,但是如果我簡單地將它留在當前配置中,寫入數據頁面將不會有實際的開銷 - 但是如何在添加新記錄時預測重建新創建的覆蓋索引的開銷? –

1

你會更好重新加工您的SQL有點開始,

SELECT 
     c.[CaseNumber], 
     isnull(convert(varchar, min(h.[CreationTimeGMT]), 101), 'N/A'), 
     ... 
FROM [Case] c 
LEFT JOIN [CaseHistory] h ON h.[CaseNumber] = c.[CaseNumber] 
GROUP BY 
     c.[CaseNumber] 
WHERE 
     h.[ActionTypeID] = 1 
    AND 
     EXISTS(
      SELECT 
        h.[CaseNumber] 
      FROM [CaseHistory] h 
      WHERE 
        h.[CaseNumber] = c.[CaseNumber] 
       AND 
        h.[ActionTypeID] <> 1 
       AND 
        h.[CreationTimeGMT] BETWEEN '10/25/2013' AND '10/25/2013'); 

一旦你這樣做,你可以看到subquer(IES/Y)的where子句是一個比較複雜的命題。

我懷疑CaseHistory你的聚集索引應保持在CaseHistoryID,因爲它的獨特性。我很想創建於

`CaseNumber`, `ActionType`, `CreationTimeGMT` 

覆蓋索引,但是,由於在子查詢中的「<> 1」,我也想嘗試翻轉的條件如

    h.[CreationTimeGMT] BETWEEN '10/25/2013' AND '10/25/2013' 
       AND 
        h.[ActionTypeID] <> 1); 

並添加此覆蓋索引也

`CaseNumber`, `CreationTimeGMT`, `ActionType` 

與以往一樣,對於性能的關鍵是首先獲得最有選擇性的條件。

我無法預測你的數據庫的實際成本,因爲我沒有你的數據,統計,環境等...

+0

+1,因爲我不反對查詢很殘酷。事實上,我們有一個CC來解決這個問題,我會在重建代碼時考慮你的方法。現在,對於被覆蓋的索引,我實際上正在通過類似的想法(在其末尾添加「ActionType」),然後修改查詢以利用「BETWEEN」和「AND」可以重建它。目前,您還會同意覆蓋索引至少會更改查詢所需的時間。如何預測新索引的寫入時間開銷? –

+0

@neoistheone,真實但可能不重要。你多久插一次行? – Jodrell

+0

它可能是大約35%的交易負載。 –