記一次分割槽表update調優過程
原始SQL:
CREATE OR REPLACE PROCEDURE sp_upd_suppressed_emails ( A_LIMIT_BULK IN PLS_INTEGER DEFAULT 2000, A_COMMIT_AFTER IN PLS_INTEGER DEFAULT 2000 ) is v_operation Varchar2(20) := 'START'; v_last PLS_INTEGER; v_start PLS_INTEGER; v_end PLS_INTEGER; l_row PLS_INTEGER; CURSOR curs_contact IS SELECT id FROM contact WHERE active_ind = 2 and suppress_flag = 'Y' and bounce_flag = 'Y' and consumer_id in (select id from consumers where login_name IN ('ASPIRAFOCUS', 'CDFW', 'PSACSFSUSR') ) and email is not null ORDER BY id; TYPE contactId IS RECORD ( id contact.id%TYPE); TYPE v_contactId_tbl IS TABLE OF contactId INDEX BY PLS_INTEGER; v_contact v_contactId_tbl; BEGIN DBMS_OUTPUT.PUT_LINE ('start reading data..' ); v_operation := 'BEFORE OPEN'; OPEN curs_contact; LOOP v_operation := 'BEFORE FETCH'; FETCH curs_contact BULK COLLECT INTO v_contact LIMIT A_LIMIT_BULK; v_operation := 'AFTER FETCH'; EXIT WHEN v_contact.COUNT = 0; v_start := 1; v_last := v_contact.COUNT; l_row := 0; LOOP DBMS_OUTPUT.PUT_LINE ('LOOP 2 top '); EXIT WHEN v_start > v_last; v_end := LEAST (v_start + A_COMMIT_AFTER - 1, v_last); DBMS_OUTPUT.PUT_LINE ('LOOP 2 v_start ' || v_start || ' end ' || v_end ); BEGIN v_operation := 'UPDATE_LOAD'; FORALL i IN v_start .. v_end UPDATE contact SET active_ind = 1, suppress_flag = 'N', bounce_flag = 'N' WHERE id = v_contact (i).id; END; DBMS_OUTPUT.PUT_LINE ('after forall start ' || v_start || ' end ' || v_end ); COMMIT; v_start := v_end + 1; END LOOP; DBMS_OUTPUT.PUT_LINE ('LOOP 2 bottom v_start ' || v_start || ' end ' || v_end ); COMMIT; END LOOP; DBMS_OUTPUT.PUT_LINE ('stop reading data..' ); EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE ('Exception:Others-> v_operation = ' || v_operation || ', rowcount # ' || l_row || ' SQLCODE ' || SQLCODE || ' ERR_MSG = ' || SUBSTR(SQLERRM, 1, 500) ); END sp_upd_suppressed_emails;
原始SQL在執行過程中經過幾小時未完成,檢視sql統計資訊:
Stat Name | Statement Total | Per Execution | % Snap Total |
---|---|---|---|
Elapsed Time (ms) | 2,997,435 | 187,339.68 | 53.56 |
CPU Time (ms) | 2,896,748 | 181,046.72 | 65.48 |
Executions | 16 |
|
|
Buffer Gets | 521,592,791 | 32,599,549.44 | 69.21 |
Disk Reads | 10,974 | 685.88 | 1.12 |
Parse Calls | 1 | 0.06 | 0.00 |
Rows | 32,000 | 2,000.00 |
|
User I/O Wait Time (ms) | 2,525 |
|
|
Cluster Wait Time (ms) | 1,146 |
|
|
Application Wait Time (ms) | 4 |
|
|
Concurrency Wait Time (ms) | 1 |
|
|
Invalidations | 0 |
|
|
Version Count | 1 |
|
|
Sharable Mem(KB) | 51 |
|
|
Execution Plan
Id | Operation | Name | Rows | Bytes | Cost (%CPU) | Time | Pstart | Pstop |
---|---|---|---|---|---|---|---|---|
0 | UPDATE STATEMENT |
|
|
|
16798 (100) |
|
|
|
1 | UPDATE | CONTACT |
|
|
|
|
|
|
2 | PARTITION RANGE ALL |
|
1 | 51 | 16798 (1) | 00:00:01 | 1 | 1048575 |
3 | PARTITION HASH SINGLE |
|
1 | 51 | 16798 (1) | 00:00:01 | KEY | KEY |
4 | TABLE ACCESS FULL | CONTACT | 1 | 51 | 16798 (1) | 00:00:01 |
|
|
表資料量非常大,根據created_date時間欄位分割槽,ID欄位進行子hash分割槽,上面建立了基於ID欄位的global hash分割槽索引。
從上面情況看出,原始SQL分批2000個ID進行批次update,但執行計劃走的是TABLE ACCESS FULL, 並且進行了分割槽的PRATITION RANGE ALL操作,可以看出2000條記錄的批次更新由於不能利用global hash分割槽索引進行檢索,主要原因是由於hash分割槽適用於等值操作,對於範圍或者批次操作,可能遍歷很多hash分割槽,導致結果不如TABLE ACCESS FULL。
針對這種情況,根據業務邏輯,將批次條件從ID改成其他非global hash索引列,執行時間降低為5分鐘。
CREATE OR REPLACE PROCEDURE sp_upd_suppressed_emails ( A_LIMIT_BULK IN PLS_INTEGER DEFAULT 2000, A_COMMIT_AFTER IN PLS_INTEGER DEFAULT 2000 ) is v_operation Varchar2(20) := 'START'; v_last PLS_INTEGER; v_start PLS_INTEGER; v_end PLS_INTEGER; l_row PLS_INTEGER; CURSOR curs_contact IS SELECT distinct email FROM contact WHERE active_ind = 2 and suppress_flag = 'Y' and bounce_flag = 'Y' and consumer_id in (select id from consumers where login_name IN ('ASPIRAFOCUS', 'CDFW', 'PSACSFSUSR') ) and email is not null ORDER BY email; TYPE contactId IS RECORD ( email contact.email%TYPE); TYPE v_contactId_tbl IS TABLE OF contactId INDEX BY PLS_INTEGER; v_contact v_contactId_tbl; v_upd_date date ; BEGIN DBMS_OUTPUT.PUT_LINE ('start reading data..' ); v_operation := 'BEFORE OPEN'; select sysdate into v_upd_date from dual; OPEN curs_contact; LOOP v_operation := 'BEFORE FETCH'; FETCH curs_contact BULK COLLECT INTO v_contact LIMIT A_LIMIT_BULK; v_operation := 'AFTER FETCH'; EXIT WHEN v_contact.COUNT = 0; v_start := 1; v_last := v_contact.COUNT; l_row := 0; LOOP DBMS_OUTPUT.PUT_LINE ('LOOP 2 top '); EXIT WHEN v_start > v_last; v_end := LEAST (v_start + A_COMMIT_AFTER - 1, v_last); DBMS_OUTPUT.PUT_LINE ('LOOP 2 v_start ' || v_start || ' end ' || v_end ); BEGIN v_operation := 'UPDATE_LOAD'; FORALL i IN v_start .. v_end UPDATE contact SET active_ind = 1, suppress_flag = 'N', bounce_flag = 'N' , modified_date = v_upd_date WHERE email = v_contact (i).email and active_ind = 2 and suppress_flag = 'Y' and bounce_flag = 'Y' and consumer_id in (select id from consumers where login_name IN ('ASPIRAFOCUS', 'CDFW', 'PSACSFSUSR') ) ; END; DBMS_OUTPUT.PUT_LINE ('after forall start ' || v_start || ' end ' || v_end ); COMMIT; v_start := v_end + 1; END LOOP; DBMS_OUTPUT.PUT_LINE ('LOOP 2 bottom v_start ' || v_start || ' end ' || v_end ); COMMIT; END LOOP; DBMS_OUTPUT.PUT_LINE ('stop reading data..' ); EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE ('Exception:Others-> v_operation = ' || v_operation || ', rowcount # ' || l_row || ' SQLCODE ' || SQLCODE || ' ERR_MSG = ' || SUBSTR(SQLERRM, 1, 500) ); END sp_upd_suppressed_emails;
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69950462/viewspace-2660047/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 記一次Oracle分割槽表全域性索引重建的過程Oracle索引
- MySQL調優之分割槽表MySql
- Oracle SQL調優之分割槽表OracleSQL
- 記一次SQL調優過程SQL
- oracle分割槽表和分割槽表exchangeOracle
- oracle分割槽表和非分割槽表exchangeOracle
- MySQL資料表分割槽手記MySql
- PostgreSQL/LightDB 分割槽表之分割槽裁剪SQL
- 記一次 500併發,平均響應時間慢-調優過程~~
- PG的非分割槽表線上轉分割槽表
- 【MYSQL】 分割槽表MySql
- Oracle drop分割槽表單個分割槽無法透過閃回恢復Oracle
- 一次 kafka 消費者的效能調優過程Kafka
- 非分割槽錶轉換成分割槽表
- [oracle] expdp 匯出分割槽表的分割槽Oracle
- Oracle分割槽表基礎運維-07增加分割槽(3列表分割槽)Oracle運維
- oracle 分割槽表move和包含分割槽表的lob moveOracle
- 移動分割槽表和分割槽索引的表空間索引
- Oracle分割槽表基礎運維-04列表分割槽Oracle運維
- Oracle分割槽表基礎運維-07增加分割槽(2 HASH分割槽)Oracle運維
- PostgreSQL分割槽表、繼承表記錄去重方法SQL繼承
- 分割槽表-實戰
- MySQL 分割槽表探索MySql
- hive學習筆記之四:分割槽表Hive筆記
- Oracle分割槽表基礎運維-06分割槽表索引Oracle運維索引
- 【Linux】MBR磁碟分割槽表只能有四個分割槽?Linux
- oracle 線上重新定義,普通表改變分割槽表,分割槽表可以更改型別、分割槽欄位等Oracle型別
- 記一次效能調優
- Oracle分割槽表基礎運維-07增加分割槽(1範圍分割槽)Oracle運維
- 調整分割槽後分割槽不見的資料找到方法
- 記一次"截圖"功能的專案調研過程!
- Oracle分割槽表基礎運維-01分割槽表分類Oracle運維
- linux交換分割槽調整Linux
- postgresql 9.6 分割槽表測試方案與記錄SQL
- Oracle分割槽表基礎運維-09刪除分割槽Oracle運維
- Oracle分割槽表基礎運維-05組合分割槽Oracle運維
- Oracle分割槽表基礎運維-02範圍分割槽Oracle運維
- Oracle分割槽表基礎運維-03HASH分割槽Oracle運維