
譯者? 湯健 · 沃趣科技數據庫技術專家
出品 ?沃趣科技

delete?/*+?index_desc(t1?t1_pk)?*/?from?t1?where?id?<=?5e6
5000000?rows?deleted.
Name?????????????????????????????????Value???????????????????????
----?????????????????????????????????-----
sorts?(rows)????????????????????????????29
我們刪除了500萬行并(有效地)沒有排序。當我們按降序遍歷索引時,優化根本不適用—我確實檢查了執行計劃是否顯示了我所指定的“索引范圍遞減掃描”。
create?index?t1_dt_open?on?t1(date_open?desc)?nologging?tablespace?test_8k_assm_2;
delete?/*+?index(t1?t1_dt_open)?*/?from?t1?where?date_open?<=?add_months(sysdate,?-60);
4999999?rows?deleted.
Name?????????????????????????????????Value
----?????????????????????????????????-----
sorts?(rows)????????????????????20,003,449
在副作用很小的范圍內,“sort (rows)”= 4 *已刪除的行:所以可以使用降序索引先嘗試刪除較新的數據——這很好,作為一個通用特性來記住可能很有用。
讓我們想象一下其他可能出錯的情況。*我在這個表上定義了一個主鍵——但是你可以使約束延遲,或者您可以簡單地創建一個非惟一索引來保護惟一(或主鍵)約束。如果我們試圖通過主鍵索引刪除,會產生什么影響?*如果我們要考慮約束,我們可能要考慮外鍵約束的影響——我們有一個client_ref列,在生產系統中,它可能是對clients表的外鍵引用。讓我們創建這個表并添加外鍵約束。*當我們使事情變得更困難時——有一個眾所周知的特性將數組處理轉換為“逐行”處理——觸發器。如果我們向表中添加行級觸發器,會產生什么效果?什么類型的觸發器(在之前/之后、插入/更新/刪除)有什么區別嗎?以下是一些結果-首先,主鍵約束的非唯一索引:alter?table?t1?drop?primary?key;
alter?table?t1?add?constraint?t1_pk?primary?key(id)
deferrable?initially?immediate
using?index?nologging?tablespace?test_8k_assm_2
;
delete?/*+?index(t1?t1_pk)?*/?from?t1?where?id?<=?5e6;
5000000?rows?deleted.
Name?????????????????????????????????Value
----?????????????????????????????????-----
sorts?(rows)?????????????????????15,000,004
在這個例子中,Oracle將我的主鍵索引設置為非惟一,作為約束可延遲的副作用,但是即使約束不可延遲,并且您只是將索引創建為非惟一,其效果也是一樣的。統計數據告訴我們,我們已經將優化應用于四個索引中的三個——快速檢查一下v$segment_statistics,就會發現它是主鍵索引,沒有進行特殊處理,它受到了超過500萬個“db塊更改”的影響。在這一點上,有必要快速檢查一下,看看通過其他索引驅動是否會改變這種情況——但是不會,這是惟一約束與非惟一索引結合的副作用。
其次,當大表是“子表”時,引用完整性的影響:create?table?t2?(
????????client_id,
????????client_name
)?as
select
????????distinct
????????????????client_ref,
????????????????rpad('x',100,'x')
from
????????t1
;
alter?table?t2?add?constraint?t2_pk?primary?key(client_id);
alter?table?t1?modify?client_ref?not?null;
alter?table?t1?add?constraint?t1_fk_t2?foreign?key?(client_ref)?references?t2(client_id);
5000000?rows?deleted.
Name?????????????????????????????????Value
----?????????????????????????????????-----
sorts?(rows)????????????????????15,002,849
我們已經排序了大約1500萬行,而通常我們需要排序2000萬行.同樣,我們可以檢查v$segment_statistics來找出哪個索引遭受了500萬的損失“db block changes”你可能不會對“外鍵”索引被逐行維護而感到驚訝-我們可能會猜測,這是某種先發制人的代碼使得Oracle必須處理“外鍵鎖定”威脅。
我們通過主鍵刪除這個特定測試的后續操作是,考慮如果我們通過外鍵索引本身刪除,或者甚至將約束修改為“on delete cascade”并刪除一些父行,將會發生什么。通過client_ref在t1上驅動delete仍然優化了其他三個索引,但是當您試圖利用“on delete cascade”機制時,這個技巧根本沒有機會產生大規模的效果。在幕后你會發現這樣的事情:delete?from?"TEST_USER"."T1"
where
?"CLIENT_REF"?=?:1
call?????count???????cpu????elapsed???????disk??????query????current????????rows
-------?------??--------?----------?----------?----------?----------??----------
Parse????????3??????0.00???????0.00??????????0??????????0??????????0???????????0
Execute???3000??????5.23??????15.37??????69349???????9238?????428052???????32510
Fetch????????0??????0.00???????0.00??????????0??????????0??????????0???????????0
-------?------??--------?----------?----------?----------?----------??----------
total?????3003??????5.23??????15.37??????69349???????9238?????428052???????32510
Rows?(1st)?Rows?(avg)?Rows?(max)??Row?Source?Operation
----------?----------?----------??---------------------------------------------------
?????0??????????0??????????0??DELETE??T1?(cr=3?pr=22?pw=0?time=9672?us)
?????7??????????8?????????11???INDEX?RANGE?SCAN?T1_CLIENT?(cr=3?pr=0?pw=0?time=125?us?cost=3?size=594?card=22)(object?id?150589)
This?output?the?consequence?of?a?bulk?delete?of?3,000?rows?from?t2?–?because?of?the?“on?delete?cascade”,?the?delete?operated?row?by?row?on?t2?and?for?each?row?Oracle?executed?a?delete?statement?against?t1.
這個輸出是t2批量刪除3000行的結果——由于“on delete cascade”,delete在t2上逐行操作,對于每一行Oracle都對t1執行一條delete語句。
從技術上講,基于數組的優化是有效的,由于索引范圍掃描,它給我們帶來了一點好處,但是數據的分散性是如此之大,以至于每次調用幾乎沒有給我們帶來任何好處。在某個階段,我們將不得不進一步探索這種父/子的關系。最后是觸發器。眾所周知,行級觸發器可以將數組處理轉換為單行處理——Oracle的索引維護優化也會發生同樣的事情嗎?create?or?replace?trigger?t1_brd
before?delete?on?t1
for?each?row
begin
????null;
end;
/
delete?/*+?index(t1?t1_pk)?*/?from?t1?where?id?<=?5e6;
5000000?rows?deleted.
Name?????????????????????????????????Value
----?????????????????????????????????-----
sorts?(rows)?????????????????????????2,639
優化完全消失了。同樣的事情也會發生在“為每一行刪除后”觸發器上,但是如果觸發器是insert或update(行級)觸發器,則不會發生這種情況。值得一提的是,索引優化也發生在索引列的值發生變化的更新上(請參閱本文),因此留給感興趣的讀者一個練習,看看哪些(如果有的話)觸發器類型允許優化在數組更新后繼續存在。
| 譯者簡介
湯健·沃趣科技數據庫技術專家
沃趣科技數據庫工程師,多年Oracle數據庫從業經驗,深入理解Oracle數據庫結構體系,現主要參與公司一體機產品安裝、測試、優化,并負責電信行業數據庫以及系統運維。
相關鏈接
MySQL 一個讓你懷疑人生的hang死現象
MySQL 執行DDL語句 hang住了怎么辦?
MySQL行級別并行復制能并行應用多少個binlog group?
binlog server還是不可靠嗎?
MySQL binlog基于時間點恢復數據失敗是什么鬼?
開源監控系統Prometheus的前世今生
prometheus監控多個MySQL實例
MySQL問題兩則
Kubernetes?scheduler學習筆記
大數據量刪除的思考(三)
大數據量刪除的思考(二)
大數據量刪除的思考(一)
統計信息記錄表|全方位認識 mysql 系統庫
數據庫對象信息記錄表|全方位認識 mysql 系統庫
訪問權限控制系統|全方位認識 mysql 系統庫
權限系統表?|?全方位認識?mysql?系統庫
Oracle RAC Cache Fusion 系列十四:Oracle RAC CR Server Part One
Oracle RAC Cache Fusion 系列十三:PCM資源訪問
Oracle RAC Cache Fusion 系列十二:Oracle RAC Enqueues And Lock Part 3
Oracle RAC Cache Fusion 系列十一:Oracle RAC Enqueues And Lock Part 2
Oracle RAC Cache Fusion 系列十:Oracle RAC Enqueues And Lock Part 1

更多干貨,歡迎來撩~