簡體   English   中英

提高Sql Delete的性能

[英]Improving performance of Sql Delete

我們有一個查詢,要根據id字段(主鍵)從表中刪除一些行。 這是一個非常簡單的查詢:

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

問題是沒有.id可能很大(例如70k),因此查詢需要很長時間。 有沒有辦法優化這個? (我們正在使用sybase - 如果這很重要)。

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

  1. 創建一個新表並復制除刪除行之外的所有行。 之后交換表格( alter table name ... )我建議即使它聽起來很愚蠢也要嘗試一下。 某些數據庫的復制速度比刪除時快得多。

  2. 對表格進行分區。 創建N個表並使用視圖將它們合並為一個。 將行排序為按刪除標准分組的不同表。 我們的想法是刪除整個表而不是刪除單個行。

我想知道解析一個包含70K項的IN子句是否有問題。 您是否嘗試過使用連接的臨時表?

考慮分批運行。 一次運行1000條記錄的循環可能比執行所有操作的一個查詢快得多,此外不會長時間將表鎖定到其他用戶。

如果您有級聯刪除(以及許多受影響的外鍵表)或涉及的觸發器,您可能需要以更小的批次運行。 您需要體驗一下,看看哪種情況最適合您的情況。 我有桌子,我必須在100個批次中刪除,其他50000個工作(幸運的是,因為我刪除了100萬條記錄)。

但是在任何情況下,我都會將我打算刪除的鍵值放入臨時表中並從那里刪除。

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

你能創建subselect而不是IN子句嗎? 這將縮短sql。 也許這可以幫助IN子句中的如此大量的值。 像這樣的東西:

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

如果數據庫模型允許,可以通過數據庫中的一些干預來加速刪除大量記錄。 以下是一些策略:

  1. 您可以通過刪除索引,刪除記錄並再次重新創建索引來加快速度。 這將在刪除記錄時消除重新平衡索引樹。

    • 刪除表上的所有索引
    • 刪除記錄
    • 重新創建索引
    • 如果你有很多與這個表的關系,如果你絕對確定delete命令不會破壞任何完整性約束,請嘗試禁用約束。 刪除速度會快得多,因為數據庫不會檢查完整性。 刪除后啟用約束。
    • 禁用完整性約束,禁用檢查約束
    • 刪除記錄
    • 啟用約束
    • 如果您有任何觸發器,並且您的業務規則允許,則禁用表上的觸發器。 刪除記錄,然后啟用觸發器。

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

我會嘗試1,2和3的組合。如果這不起作用,那么4.如果一切都很慢,我會尋找更大的盒子 - 更多的內存,更快的磁盤。

找出什么在用盡性能!

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

  • 那張桌子上有外鍵嗎? 確保引用ID已編入索引
  • 那張桌子上有索引嗎? 可能是在刪除之前刪除並在刪除之后重新創建可能更快。
  • 檢查執行計划。 它是否使用全表掃描可能更快的索引? 或者反過來說? 提示可能有所幫助
  • 如上所述,創建表可能更快,而不是像上面建議的那樣選擇到new_table。

但請記住:首先找出正在消耗性能的因素。

使用DDL語句時,請確保了解並接受它可能對事務和備份產生的后果。

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

如果您要執行“從...中刪除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

嘗試按照與表相同的順序對傳入的ID進行排序,或者存儲索引。然后,您可以在磁盤緩存上獲得更多命中。

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

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

our_table是否有關於刪除級聯的參考?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM