delete 與全表掃描
delete 與全表掃描
先建立一張測試用的表。並填充資料。把表造的大小才有比較的效果。
SQL> create table testing01 (id number(8),col2 varchar2(30));
Table created.
SQL> begin
2 for i in 1..1000000
3 loop
4 insert into testing01 values(i,'This is a testing record');
5 end loop;
6 commit;
7 end;
8 /
PL/SQL procedure successfully completed.
透過下面的查詢對剛才建立的表有一個基本的認識。
SQL> select segment_name,blocks,bytes/1024 as "Size[KB]"
2 from user_segments
3 where segment_name = 'TESTING01';
SEGMENT_NAME BLOCKS Size[KB]
--------------- ---------- ----------
TESTING01 4992 39936
計算HWM(high water mark),所謂的高水位線用來界定segment 中已經使用過的block 與沒有使用的block.已經使用的block 中不一定實際的儲存有資料。
SQL> select blocks from user_segments
2 where segment_name = 'TESTING01';
BLOCKS
----------
4992
SQL> analyze table testing01 estimate statistics;
Table analyzed.
SQL> select empty_blocks
2 from user_tables
3 where table_name = 'TESTING01';
EMPTY_BLOCKS
------------
86
hwm =total_blocks – unused_blocks – 1.
HWM=4905
在segment testing01。使用使用過的block 數量是4905.執行如下的查詢檢視執行計劃。
SQL> set autotrace traceonly
SQL> select * from testing01;
1000000 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 3696461997
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1013K| 27M| 1512 (13)| 00:00:19 |
| 1 | TABLE ACCESS FULL| TESTING01 | 1013K| 27M| 1512 (13)| 00:00:19 |
-------------------------------------------------------------------------------
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
74301 consistent gets
315 physical reads
201404 redo size
43646886 bytes sent via SQL*Net to client
733745 bytes received via SQL*Net from client
66668 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1000000 rows processed
把表中的記錄全部delete ,在確定該表對應的segment 的HWM.
SQL> delete from testing01;
1000000 rows deleted.
SQL> select blocks from user_segments
2 where segment_name = 'TESTING01';
BLOCKS
----------
4992
SQL> select blocks from user_segments
2 where segment_name = 'TESTING01';
BLOCKS
----------
4992
SQL> select empty_blocks
2 from user_tables
3 where table_name = 'TESTING01';
EMPTY_BLOCKS
------------
86
透過查詢和使用公式hwm =total_blocks – unused_blocks – 1.
我們可以知道hwm 沒有下降,hwm 之所以沒有下降的原因是保留
這部分空間為了以後的update,insert 的需要。在這種情況下進行
全部掃描會是怎樣的情形呢?
SQL> alter system flush shared_pool;
System altered.
SQL> alter system flush buffer_cache;
System altered.
SQL> select * from testing01;
no rows selected
Execution Plan
----------------------------------------------------------
Plan hash value: 3696461997
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1013K| 27M| 1512 (13)| 00:00:19 |
| 1 | TABLE ACCESS FULL| TESTING01 | 1013K| 27M| 1512 (13)| 00:00:19 |
-------------------------------------------------------------------------------
Statistics
----------------------------------------------------------
711 recursive calls
0 db block gets
4964 consistent gets
4869 physical reads
0 redo size
340 bytes sent via SQL*Net to client
408 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
13 sorts (memory)
0 sorts (disk)
0 rows processed
SQL> set autotrace off
我們知道表中沒有資料。透過執行計劃我們可以知道這條sql 語句在執行的時候還是進行了。全表掃描讀取了很多的資料塊。因為oracle 在執行全表掃描的時候會讀取物件對應的segment中第一個block 到HWM之間的blocks。因為delete 不會降低HWM ,所以sql 執行的時候如果
要進行全表掃描,那麼oracle 很”無辜“需要多做很多額外的IO操作。為了不讓oracle 無辜的讀取那些在HWM下沒有資料的block,我們需要嘗試降低HWM。可選的方式如下。
1、truncate 一張表,降低HWM 釋放空間。如果表空中的資料都不再需要可以選用這種方式。
當時如果我想要刪除某些行這種方式就不行了。在很多時候可以結合表分割槽技術。
2、使用shrink 的方式,但是會導致索引的無效對index 需要rebuilt.步驟比較多。
3、把表drop 了重建。這可能是最爛的方式,因為要考慮到表之間複雜的參照關係,資料的填充花費的時間和系統資源。
對testing01 進行shrink。我沒有建立索引所以不需要對索引進行rebuilt.
SQL> alter table testing01 move;
Table altered.
SQL> select blocks from user_segments
2 where segment_name = 'TESTING01';
BLOCKS
----------
8
SQL> analyze table testing01 estimate statistics;
Table analyzed.
SQL> select empty_blocks
2 from user_tables
3 where table_name = 'TESTING01';
EMPTY_BLOCKS
------------
8
乖乖,現在HWM線下來了回到了表最初建立的時候的樣子指向segment 中第一個block的左邊。
今日心得
有時候進行全表掃描是好事,或者說是不可避免的。但是在上面這種情況(或者表中經常進行大量delete 的操作)下就糟糕了,因為oracle在執行sql 語句的時候很無辜需要讀取高水位線以下的很多空白的block 做無用功。我們應該考慮透過那些方式避免這種情況的出現。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/26110315/viewspace-722053/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- delete 刪除資料 全表掃描還是掃描所有塊的測試delete
- oracle 全表掃描,索引範圍掃描與塊的理解Oracle索引
- 優化全表掃描優化
- MySQL中的全表掃描和索引樹掃描MySql索引
- ORACLE全表掃描查詢Oracle
- 使用索引快速全掃描(Index FFS)避免全表掃描的若干場景索引Index
- 查詢全表掃描語句
- oracle優化:避免全表掃描Oracle優化
- 查詢全表掃描的sqlSQL
- Oracle中存取資料掃描Table及索引的方式(全表掃描,索引掃描等)Oracle索引
- (轉)索引掃描還是全表掃描(Index Scan Or Full Table Scan)索引Index
- 轉)索引掃描還是全表掃描(Index Scan Or Full Table Scan)索引Index
- 累計的力量,delete全表掃描導致程式執行時間過長。delete
- 抓取全表掃描的表,篩選和分析
- 索引全掃描和索引快速全掃描的區別索引
- 全表掃描的cost 與 索引掃描Cost的比較 – 無直方圖(10.1.0.3以後)索引直方圖
- oracle是如何進行全表掃描的Oracle
- 優化Oracle with全表掃描的問題優化Oracle
- 24_Oracle資料庫全表掃描詳解(四)_全表掃描生產最佳化案例三則Oracle資料庫
- oracle實驗記錄(分割槽全表掃描(全區掃描) FTS 時候的成本計算)Oracle
- 隱形轉換導致全表掃描案例
- 一條全表掃描sql語句的分析SQL
- 優化Oracle with全表掃描的問題(二)優化Oracle
- 使用全表掃描快取大表的相關問題快取
- 有索引卻走全表掃描的實驗分析索引
- noworkload下全表掃描cost的計算
- oracle sql tuning 8--優化全表掃描OracleSQL優化
- 【MySQL】全索引掃描的bugMySql索引
- 23_Oracle資料庫全表掃描詳解(三)Oracle資料庫
- 22_Oracle資料庫全表掃描詳解(二)Oracle資料庫
- 21_Oracle資料庫全表掃描詳解(一)Oracle資料庫
- 關係型資料庫全表掃描分片詳解資料庫
- 關於分割槽表中的全partition掃描問題
- 使用10046 event trace跟蹤全表掃描操作
- oracle實驗記錄 (全表掃描COST計算方法)Oracle
- Greenplum儲存過程使用分割槽表將進行全表掃描儲存過程
- PostgreSQL DBA(55) - MVCC#8(對全表掃描的影響)SQLMVCC#
- MongoDB Primary 為何持續出現 oplog 全表掃描?MongoDB