2012-08-14 27 views
1

我有一些數據,其中將每個版本的150萬行的「版本」表,其結構是:批量複製一部分本身在SQL Server

[ID] bigint, 
[version] int, 
[somecolumn] int, 
[anothercolumn] int, 
[thirdcolumn] tinyint 

我不斷需要一個版本複製到另一個版本是這樣的查詢會做:

INSERT INTO myTable 
    (SELECT ID, version + 1, somecolumn, anothercolumn, thirdcolumn 
    FROM myTable 
    WHERE version = @version) 

但問題是,這表現相當慢,就像每運行10秒以上。以閃電般的速度進行此項操作的最佳方式是什麼?我已經嘗試選擇到一個臨時表,並從那裏合併,但沒有做任何更快..

+0

你可以發佈計劃和行計數? – usr 2012-08-14 08:16:52

+0

行數每一次操作150萬行。幾個索引,但我認爲他們在這裏沒有關係,因爲他們可以被禁用和啓用 – Jaska 2012-08-14 08:58:01

回答

1

的幾點思考:

  1. 使用臨時表是不太可能的幫助。這將是神奇的。
  2. 使用NOLOCK不太可能有所幫助。我看不到任何證據表明這是一個阻塞問題,因爲只有一個併發事務(至少在測試系統上)。
  3. 不確定爲什麼重建索引的速度比維護速度快。你的桌子可能只有很少的幾個版本?如果你得到很多索引,重建會變得越來越慢。不是一個長期的解決方案。
  4. 嘗試將聚簇索引鍵更改爲(Version,ID),以便插入是連續的。隨機DML比順序DML慢得多。
+0

終於有人對這個東西有深刻的瞭解!我已經將主鍵定義爲(版本,ID)。也許我只需重新設計我的東西,以便爲[Version_1],[Version_2]等每個版本創建一個新表,並在存儲過程中使用動態SQL來使用這些數據。 – Jaska 2012-08-14 09:29:07

+0

你知道,每秒150k行插入速度是一個非常好的數字。你無法將這個速度提高一個數量級,這是肯定的。證明:在只有CI的新鮮空表中運行插入並測量速度。這是你可以得到的最大速度。順便說一句,爲什麼你需要這麼快完成一個150萬(!)行操作?這樣的事情應該相當罕見?! – usr 2012-08-14 09:34:13

+0

如果您確實需要優化這一點,請考慮具有多個表格或分區的解決方案(它正在完全實現該功能)。這使您可以構建新的索引而不是維護現有的索引。 – usr 2012-08-14 09:35:42

0

您是否已添加索引到版本列?這應該會加快速度。

CREATE INDEX IDX_tableName_VERSION ON tableName (version) 

UPDATE

如何使用上表NOLOCK讀?如果您認爲您可以從其他交易中對您的系統進行骯髒讀取,則無效。之前我已經有了一些成功,只需要小心使用它!

INSERT INTO myTable 
    (SELECT ID, version + 1, somecolumn, anothercolumn, thirdcolumn 
    FROM myTable WITH(NOLOCK) 
    WHERE version = @version) 
+1

是有索引,但我相信在INSERT操作索引實際上使插入性能更低 – Jaska 2012-08-14 07:45:30

+1

我正在查看聲明的選擇部分。每個操作10秒似乎過多,所以我認爲版本列沒有在查詢的選擇部分使用的索引。 – XN16 2012-08-14 08:07:54

+0

這是插入1,5百萬行需要10〜15秒..這就是爲什麼我正在尋找一些真正的快速「批量」操作。我計算出,150萬x行大小隻是~30兆字節,所以它不應該花那麼長的時間。 – Jaska 2012-08-14 08:55:38

0

看看是否有效。

begin 
    SELECT ID, version + 1, somecolumn, anothercolumn, thirdcolumn 
    into #temp 
    FROM myTable 
    WHERE version = @version 

    ALTER INDEX IDX_tableName_VERSION ON tableName.version DISABLE 

    INSERT INTO myTable 
    select * from #temp 

    ALTER INDEX IDX_tableName_VERSION ON tableName.version ENABLE 

end 
+0

刪除索引將時間分割一半,但#temp表不會爲實際查詢帶來任何實際性能增益。我得到的最好結果(5秒)是,如果我只是爲每個版本創建一個新表,但涉及到使用一些不太好的動態SQL .. – Jaska 2012-08-14 08:51:25

+0

你可以通過直接添加記錄到myTable而不是#索引後的Temp是否被禁用? – 2012-08-14 09:10:25

+0

是的,在禁用索引之後,直接向myTable比使用#temp表的速度大約慢了2秒 – Jaska 2012-08-14 09:18:57