2009-11-20 102 views
1

訪問我的一個表時,我需要一些重新分解諮詢我遇到了巨大的進展緩慢。對不起,如果這不是這種事情的正確領域。大表建議(SQL Server)的

我工作的一個項目,旨在爲我們的內部服務器的服務器性能統計報表。我每天晚上處理Windows性能日誌(12臺服務器,10臺性能計數器和每15秒記錄一次)。我將數據存儲在一個表中,如下所示:

CREATE TABLE [dbo].[log](
    [id] [int] IDENTITY(1,1) NOT NULL, 
    [logfile_id] [int] NOT NULL, 
    [test_id] [int] NOT NULL, 
    [timestamp] [datetime] NOT NULL, 
    [value] [float] NOT NULL, 
CONSTRAINT [PK_log] PRIMARY KEY CLUSTERED 
(
    [id] ASC 
)WITH FILLFACTOR = 90 ON [PRIMARY] 
) ON [PRIMARY] 

目前有16,529,131行,它將繼續增長。

我訪問以產生報告和創建從ColdFusion的曲線圖,像這樣的數據:

SET NOCOUNT ON 

CREATE TABLE ##RowNumber (RowNumber int IDENTITY (1, 1), log_id char(9)) 

INSERT ##RowNumber (log_id) 
SELECT l.id 
FROM log l, logfile lf 
WHERE lf.server_id = #arguments.server_id# 
and l.test_id = #arguments.test_id#" 
and l.timestamp >= #arguments.report_from# 
and l.timestamp < #arguments.report_to# 
and l.logfile_id = lf.id 
order by l.timestamp asc 

select rn.RowNumber, l.value, l.timestamp 
from log l, logfile lf, ##RowNumber rn 
where lf.server_id = #arguments.server_id# 
and l.test_id = #arguments.test_id# 
and l.logfile_id = lf.id 
and rn.log_id = l.id 
and ((rn.rownumber % #modu# = 0) or (rn.rownumber = 1)) 
order by l.timestamp asc 

DROP TABLE ##RowNumber 

SET NOCOUNT OFF 

(不CF開發者#value#插入value##映射到#

我基本上創建臨時表以便我可以使用rownumber來選擇每x行。通過這種方式,我只選擇了我可以顯示的行數。這有幫助,但它仍然非常緩慢。

SQL Server Management Studio中告訴我,我的索引的情況如下(我對使用幾乎沒有知識指數的正常):

IX_logfile_id (Non-Unique, Non-Clustered) 
IX_test_id (Non-Unique, Non-Clustered) 
IX_timestamp (Non-Unique, Non-Clustered) 
PK_log (Clustered) 

我會很感激的人誰可以給一些建議,可以幫助我加快了一點。我不介意重新組織東西,並且我完全控制了這個項目(儘管可能不在服務器硬件上)。

乾杯(抱歉長後)

+2

順便說一句,1600萬行很大,但決不是不可能的。我們在這裏有一個SQL Server數據庫,其中包含大約10億行的表格,而且我們仍然可以在不到一秒的時間內完成查詢。正如你推斷的那樣,索引在這裏非常重要。 – 2009-11-20 16:39:43

+0

丹尼爾是正確的,我們的數據倉庫建立在一個sql服務器平臺上,我們經常在包含3.5億行的表上報告(也很快)。 – 2009-11-20 16:43:10

+0

我很高興我不負責你的數據庫,我不知道從哪裏開始!有趣的是,我在大學學習了數據庫設計,作爲我的CS課程的一部分,但他們甚至沒有涉及索引或任何類型的實際數據維護,真的令人失望。 – OrganicPanda 2009-11-23 10:00:54

回答

4

你的問題是,你選擇了一個糟糕的聚集鍵。沒有人有興趣通過ID檢索一個特定的日誌值。我的系統是象別的我見過的,那麼所有的查詢要問:在一個日期範圍

  • 所有計數器對所有服務器上的所有服務器
  • 特定的計數器值的範圍日期
  • 一臺服務器的所有計數器在一定範圍的日期
  • 特定服務器的特定計數器超過一定範圍的日期

由於表的大小,你的所有非聚集索引是無用的。他們都會打到index tipping point,有保證,所以他們可能不存在。我假設你所有的非聚集索引被定義爲名稱中字段的簡單索引,不包含字段。

我會假裝我其實知道你的要求。你必須忘記關於存儲的常識,並且實際上覆制每個非聚集索引中的所有數據。這裏是我的建議:

  • 刪除[id]上的聚集索引,是一樣沒用的,因爲它得到。
  • 用聚簇索引(logfile_it,test_id,timestamp)組織表。上(爲test_id,logfile_id,時間戳)
  • 非clusterd指數包括(logfile_id,時間戳)(值)
  • NC指數包括(值)
  • 上(爲test_id,時間戳)包括(值)
  • NC指數
  • 上(時間戳)NC指標包括:(值)
  • 添加維護任務,定期重新組織所有索引,因爲它們容易產生碎片

聚集索引覆蓋了查詢的特定計數器值的歷史在特定的機'。非聚集索引涵蓋了其他各種可能的查詢(隨着時間的推移,一臺機器上的所有計數器,隨時間推移的所有機器上的特定計數器等)。

你注意到我沒有評論你的查詢腳本。這是因爲世界上沒有任何東西可以使查詢在您擁有的表結構上運行得更快。

現在你不應該做的一件事實際上是實施我的建議。我說我打算假裝我知道你的要求。但我其實並沒有。我剛剛舉了一個可能的結構的例子。你真正應該做的是研究該問題,並找出正確的索引結構爲您的要求:

同樣在 '覆蓋索引' 一個谷歌帶來了不少好文章。

當然,在一天結束時,存儲空間並不是免費的,所以您必須平衡要求在每個可能的組合上都有一個非聚集索引,並且需要檢查數據庫的大小。幸運的是,你有一個非常小而狹窄的表格,所以在許多非聚集索引上覆制它並不是什麼大不了的事情。另外我不會關心插入性能,在15秒時120個計數器每個意味着每秒8-9個插入,這沒什麼。

+0

優秀的答案!非常感謝您的建議和鏈接。我會進一步研究這個問題,但你給了我一個很好的起點。 – OrganicPanda 2009-11-23 09:18:09

+0

對不起,最後一件事。我只是試圖消化你的建議,並且當你說'非test_id,logfile_id,timestamp包含(value)'你是否有'test_id,logfile_id,timestamp,value'的NC索引有一個特殊的機制來包含一列。對不起,我只是有點困惑,因爲它不在列表中與其他列,再次感謝。 – OrganicPanda 2009-11-23 11:42:23

+0

自SQL 2005以來,有一種特殊的機制可以包含列。在2000年,你必須將「包含」列添加到索引鍵本身。 – 2009-11-23 16:28:28

1

有兩件事情浮現在腦海中。

  1. 您是否需要保留那麼多數據?如果不是,請考慮創建一個歸檔表(如果要保留它)(但不要僅在每次運行查詢時將其與主表聯接)。

  2. 我會避免使用具有這麼多數據的臨時表。請參閱關於臨時表性能的文章以及如何避免使用它們。

http://www.sql-server-performance.com/articles/per/derived_temp_tables_p1.aspx

  • 您似乎缺少在SERVER_ID字段的索引。我會考慮使用這個字段和其他字段來創建一個覆蓋索引。這裏還有一篇文章。
  • http://www.sql-server-performance.com/tips/covering_indexes_p1.aspx

    編輯

  • 隨着在表中在如此短的時間內,許多行,我也查詢索引碎片,其可能是緩慢的原因。在SQL Server 2000中,您可以使用DBCC SHOWCONTIG命令。
  • 請參閱此鏈接信息http://technet.microsoft.com/en-us/library/cc966523.aspx

    而且,請注意,我有編號這些項目爲1,2,3,4但是編輯器會自動重置他們

    +0

    偉大的鏈接! 1.到目前爲止,我有4個月的數據,理想情況下,我希望在當前表中保留6個月,然後我可以考慮歸檔。 2.我將使用該方法運行一些測試 (再次)。 server_id是另一個表(稱爲日誌文件)的一部分。每臺服務器有多個日誌文件,每個日誌文件有多個日誌。我是否仍然可以在索引中包含這些內容? – OrganicPanda 2009-11-20 16:13:51

    +0

    不,如果它在不同的表中,則無法將此字段包含在覆蓋索引中。我用另外一點更新了我的答案。 – 2009-11-20 16:32:37

    +0

    運行這些檢查後,我發現我的邏輯掃描碎片爲2.3%,範圍掃描碎片爲0.11%。根據該文件,我的頁面密度爲90%,這是一個健康的數量。這些數字對我來說看起來不錯,但我會確保按照該文檔的建議添加碎片整理。 – OrganicPanda 2009-11-23 09:51:07

    0

    有一次,當仍然工作SQL服務器2000,我需要做一些分頁,並且我遇到了一種分頁方法,這種分頁方法真的讓我大惑不解。看看這個方法。

    DECLARE @Table TABLE(
         TimeVal DATETIME 
    ) 
    
    DECLARE @StartVal INT 
    DECLARE @EndVal INT 
    
    SELECT @StartVal = 51, @EndVal = 100 
    
    SELECT * 
    FROM (
          SELECT TOP (@EndVal - @StartVal + 1) 
            * 
          FROM (
             --select up to end number 
             SELECT TOP (@EndVal) 
               * 
             FROM @Table 
             ORDER BY TimeVal ASC 
            ) PageReversed 
          ORDER BY TimeVal DESC 
         ) PageVals 
    ORDER BY TimeVal ASC 
    

    舉個例子

    SELECT * 
    FROM (
          SELECT TOP (@EndVal - @StartVal + 1) 
            * 
          FROM (
             SELECT TOP (@EndVal) 
               l.id, 
               l.timestamp 
             FROM log l, logfile lf 
             WHERE lf.server_id = #arguments.server_id# 
             and l.test_id = #arguments.test_id#" 
             and l.timestamp >= #arguments.report_from# 
             and l.timestamp < #arguments.report_to# 
             and l.logfile_id = lf.id 
             order by l.timestamp asc 
            ) PageReversed ORDER BY timestamp DESC 
         ) PageVals 
    ORDER BY timestamp ASC 
    
    +0

    這看起來像一個很好的方式來模擬MySQL限制功能,我非常想念!問題是我不知道我想要的數據在哪裏,我必須在日期之間找到數據,並且數據並不總是按照正確的順序排列的,所以我不認爲我現在可以使用它,但我肯定會保存以備後用。 – OrganicPanda 2009-11-20 16:18:39

    +0

    請參閱編輯示例,因爲我會嘗試它。 – 2009-11-20 16:26:42

    +0

    工作起來非常快!我會看看我能否使用它。非常感謝! – OrganicPanda 2009-11-23 09:57:58