6

我們有一個基於id字段(主鍵)從表中刪除一些行的查詢。這是一個非常簡單的查詢:(如70K)提高Sql Delete的性能

delete all from OUR_TABLE where ID in (123, 345, ...) 

問題是節數IDS可以是巨大的,所以查詢需要較長的時間。有什麼辦法可以優化嗎? (我們正在使用sybase - 如果這很重要)。

+0

這是ASE或ASA?你知道你的版本號嗎? – AdamH 2009-02-24 14:08:02

+0

它是ASE版本10x。 – amit 2009-02-25 03:08:53

回答

3

請考慮分批運行。一次循環運行1000條記錄可能比一個查詢執行任何操作都快得多,並且此外不會將表格一直鎖定在其他用戶處。

如果您有級聯刪除(以及大量受影響的外鍵表)或觸發器,您可能需要以更小的批次運行。你必須體驗一下,看看哪個是你的情況的最佳數字。我已經有了一些表格,我不得不分批刪除100個表格,其中有50000個工作表格(有幸在這種情況下,我刪除了一百萬條記錄)。

但在任何連我會把我打算刪除到一個臨時表,並從那裏刪除我的鍵值。

3

我想知道是否解析IN中有70K條目的子句是一個問題。你是否嘗試過使用連接的臨時表?

+0

不知道Sybase,但在SQLServer中,這也是我第一次嘗試優化刪除。 – 2009-02-23 10:58:07

0

請問our_table有刪除級聯的參考嗎?

4

有兩種方法可以使像這樣的語句執行:

  1. 創建一個新表,並複製所有,但刪除行。之後交換表格(alter table name ...)我建議嘗試一下,即使聽起來很愚蠢。有些數據庫在複製時比在刪除時快得多。

  2. 分區你的表。創建N個表並使用視圖將它們合併成一個表。將行按照刪除標準分組到不同的表中。這個想法是刪除整個表而不是刪除單個行。

+0

+1這是我的建議。 – Elijah 2009-02-23 11:38:14

2

Sybase可以處理IN子句中的70K個參數嗎?我使用的所有數據庫對於IN子句的參數數量都有一些限制。例如,Oracle有大約1000個的限制。

您可以創建子選擇而不是IN子句嗎?這將縮短SQL。也許這可能有助於IN子句中的大量值。事情是這樣的:

DELETE FROM OUR_TABLE WHERE ID IN 
     (SELECT ID FROM somewhere WHERE some_condition) 

刪除大量記錄,可以加快與數據庫中的一些干預措施,如果數據庫模型許可證。這裏有一些策略:

  1. 你可以通過刪除索引,刪除記錄和重新創建索引來加快速度。這將消除重新平衡索引樹,同時刪除記錄。

    • 滴上表的所有索引
    • 刪除記錄
    • 重新創建索引
    • 如果你有很多的關係到此表,嘗試禁用限制,如果你是絕對相信,delete命令不會破壞任何完整性約束。因爲數據庫不會檢查完整性,所以刪除將變得更快。刪除後啓用約束。
    • 禁用完整性約束,禁用檢查約束
    • 刪除記錄
    • 啓用約束
    • 禁止觸發器的表,如果您有任何,如果您的業務規則允許的。刪除記錄,然後啓用觸發器。

    • 最後,按照其他建議 - 製作包含不會被刪除的行的表的副本,然後刪除原始,重命名副本並重新創建完整性約束(如果有)。

我會嘗試的1,2和3的組合。如果還是不行,那麼4.如果一切都慢,我會尋找更大的盒子 - 更多的內存,更快的磁盤。

+0

禁用觸發器是一個非常糟糕的主意,除非您能夠阻止其他用戶在禁用數據庫時對其執行操作。 – HLGEM 2009-02-23 14:28:46

+0

我知道,這就是爲什麼我寫了「如果你的商業規則允許的話」。例如,我看到很多數據庫中使用觸發器進行某種審計更改。如果他需要表現,可能會消除這種觸發器。 – zendar 2009-02-23 15:05:47

2

找出什麼是使用了性能!

在很多情況下,你可以使用所提供的解決方案之一。但也可能有其他的(基於Oracle的知識,所以在其他數據庫上會有所不同)編輯:剛剛看到你提到了sybase:

  • 你有那張表的外鍵嗎?確保引用ID已編入索引
  • 您是否在該表上有索引?可能是在刪除之前刪除並在刪除之後重新創建可能會更快。
  • 檢查執行計劃。它是否使用全表掃描可能更快的索引?或者相反呢? HINTS可以幫助
  • ,而不是選擇到NEW_TABLE創建一個表作爲選擇上述的建議可能會更快。

但請記住:找出什麼是性能優先使用。

當您使用DDL語句確保您理解並接受它可能對交易和備份的後果。

1

嘗試按照與表格相同的順序對要傳入的「ID」進行排序,或者存儲索引。然後,您可以在磁盤緩存中獲得更多匹配。

將要刪除的ID放入臨時表中,該表的Ids按與主表相同的順序排序,可讓數據庫在主表上進行簡單掃描。

您可以嘗試使用多於一個連接,並通過連接吐出工作以便使用數據庫服務器上的所有CPU,但是請考慮先取出哪些鎖等。

1

我也認爲,臨時表可能是最好的解決方案。

但是,如果您要執行「從...刪除ID(從...中選擇ID)」,那麼對於大型查詢它仍然會很慢。因此,我建議您使用連接刪除 - 許多人不知道該功能。

因此,鑑於此示例表:

-- set up tables for this example 
    if exists (select id from sysobjects where name = 'OurTable' and type = 'U') 
     drop table OurTable 
    go 

    create table OurTable (ID integer primary key not null) 
    go 
    insert into OurTable (ID) values (1) 
    insert into OurTable (ID) values (2) 
    insert into OurTable (ID) values (3) 
    insert into OurTable (ID) values (4) 
    go 

然後,我們可以寫我們的刪除代碼如下:

create table #IDsToDelete (ID integer not null) 
    go 
    insert into #IDsToDelete (ID) values (2) 
    insert into #IDsToDelete (ID) values (3) 
    go 
    -- ... etc ... 
    -- Now do the delete - notice that we aren't using 'from' 
    -- in the usual place for this delete 
    delete OurTable from #IDsToDelete 
     where OurTable.ID = #IDsToDelete.ID 
    go 
    drop table #IDsToDelete 
    go 
    -- This returns only items 1 and 4 
    select * from OurTable order by ID 
    go