批量修改資料後應收集統計資訊
今天幫朋友定位了一個問題,導致問題的主要原因是統計資訊不準確。
簡單描述一下問題,朋友的資料庫中錯誤的匯入了幾百萬的記錄,需要通過DELETE操作刪除這些資料,但是發現即使是查詢都異常緩慢,更不要說刪除了。
等上去檢查後發現,Oracle給出了一個非常低效的執行計劃,將兩個BTREE索引轉化為BITMAP索引,然後進行BITMAP AND操作,再將得到的BITMAP索引轉化為BTREE索引,然後根據索引對錶進行掃描。
通過INDEX_JOIN方式執行COUNT(*)操作,發現滿足查詢條件的記錄超過了400萬。顯然利用這個執行計劃,效率是十分低下的。
導致問題的主要原因就是由於在匯入大量的資料後,沒有重新收集統計資訊,Oracle仍然使用舊的統計資訊,因此認為這種執行計劃會很高效,而實際上匯入的400萬記錄都是滿足兩個索引欄位查詢條件的。
文字描述比較抽象,下面通過一個例子來簡單描述這個問題:
SQL> CREATE TABLE T (
2 ID NUMBER,
3 NAME VARCHAR2(30),
4 TYPE VARCHAR2(30),
5 OTHER VARCHAR2(4000));
表已建立。
SQL> CREATE INDEX IND_T_NAME
2 ON T(NAME);
索引已建立。
SQL> CREATE INDEX IND_T_TYPE
2 ON T(TYPE);
索引已建立。
SQL> INSERT INTO T
2 SELECT ROWNUM,
3 OBJECT_NAME,
4 OBJECT_TYPE,
5 LPAD('A', 2000, 'A')
6 FROM ALL_OBJECTS;
已建立69406行。
SQL> UPDATE T
2 SET NAME = 'T'
3 WHERE TYPE = 'SYNONYM';
已更新27696行。
SQL> COMMIT;
提交完成。
SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS(USER, 'T')
PL/SQL 過程已成功完成。
構造了一張大表,前面的UPDATE語句是為了一會的查詢採用BITMAP INDEX AND執行計劃,而不是單獨掃描其中一個索引:
SQL> SET AUTOT TRACE
SQL> SELECT *
2 FROM T
3 WHERE NAME = 'T'
4 AND TYPE = 'TABLE';
執行計劃
----------------------------------------------------------
Plan hash value: 4030788717
--------------------------------------------------------------------------------------------
| Id| Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 2031 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID | T | 1 | 2031 | 2 (0)| 00:00:01 |
| 2 | BITMAP CONVERSION TO ROWIDS | | | | | |
| 3 | BITMAP AND | | | | | |
| 4 | BITMAP CONVERSION FROM ROWIDS| | | | | |
|*5 | INDEX RANGE SCAN | IND_T_NAME | 2 | | 1 (0)| 00:00:01 |
| 6 | BITMAP CONVERSION FROM ROWIDS| | | | | |
|*7 | INDEX RANGE SCAN | IND_T_TYPE | 2 | | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
5 - access("NAME"='T')
7 - access("TYPE"='TABLE')
統計資訊
----------------------------------------------------------
1 recursive calls
0 db block gets
49 consistent gets
0 physical reads
0 redo size
2746 bytes sent via SQL*Net to client
519 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
可以看到,更加當前的統計資訊,採用BITMAP INDEX AND是很高效的,因為這時只返回1條記錄。
SQL> SET AUTOT OFF
SQL> INSERT INTO T
2 SELECT 100000 + ROWNUM,
3 'T',
4 'TABLE',
5 LPAD('A', 2000, 'A')
6 FROM ALL_OBJECTS;
已建立69406行。
SQL> COMMIT;
提交完成。
載入了大量的資料都是滿足NAME = ‘T’和TYPE = ‘TABLE’的條件。
再次執行查詢:
SQL> SET AUTOT TRACE
SQL> SET TIMING ON
SQL> SELECT *
2 FROM T
3 WHERE NAME = 'T'
4 AND TYPE = 'TABLE';
已選擇69407行。
已用時間: 00: 00: 09.41
執行計劃
----------------------------------------------------------
Plan hash value: 4030788717
--------------------------------------------------------------------------------------------
| Id| Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 2031 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID | T | 1 | 2031 | 2 (0)| 00:00:01 |
| 2 | BITMAP CONVERSION TO ROWIDS | | | | | |
| 3 | BITMAP AND | | | | | |
| 4 | BITMAP CONVERSION FROM ROWIDS| | | | | |
|*5 | INDEX RANGE SCAN | IND_T_NAME | 2 | | 1 (0)| 00:00:01 |
| 6 | BITMAP CONVERSION FROM ROWIDS| | | | | |
|*7 | INDEX RANGE SCAN | IND_T_TYPE | 2 | | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
5 - access("NAME"='T')
7 - access("TYPE"='TABLE')
統計資訊
----------------------------------------------------------
1 recursive calls
0 db block gets
14140 consistent gets
0 physical reads
0 redo size
141756898 bytes sent via SQL*Net to client
51416 bytes received via SQL*Net from client
4629 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
69407 rows processed
由於統計資訊沒有更新,Oracle仍然選擇了轉化BITMAP索引的執行計劃,因為Oracle並不知道資料發生的變化,而如果載入資料後對錶進行分析,則不會導致這種情況的出現:
SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS(USER, 'T')
PL/SQL 過程已成功完成。
已用時間: 00: 00: 02.07
SQL> SELECT *
2 FROM T
3 WHERE NAME = 'T'
4 AND TYPE = 'TABLE';
已選擇69407行。
已用時間: 00: 00: 09.15
執行計劃
----------------------------------------------------------
Plan hash value: 1601196873
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 47170 | 90M| 7451 (1)| 00:01:45 |
|* 1 | TABLE ACCESS FULL| T | 47170 | 90M| 7451 (1)| 00:01:45 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("TYPE"='TABLE' AND "NAME"='T')
統計資訊
----------------------------------------------------------
1 recursive calls
0 db block gets
23818 consistent gets
0 physical reads
0 redo size
1544905 bytes sent via SQL*Net to client
51416 bytes received via SQL*Net from client
4629 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
69407 rows processed
收集統計資訊後,Oracle不在選擇索引掃描,而是選擇全表掃描。這個例子的資料量比較小,因此兩個執行計劃之間的差別不大,對於一個幾千萬的大表而言,二者的差別就十分驚人了。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4227/viewspace-663590/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 收集資料庫統計資訊需要收集直方圖資訊.資料庫直方圖
- 6 收集資料庫統計資訊資料庫
- oracle統計資訊 使用dbms_stats包收集統計資料Oracle
- Oracle收集統計資訊Oracle
- Oracle 統計資訊收集Oracle
- 收集oracle統計資訊Oracle
- ORACLE 收集統計資訊Oracle
- 【統計資訊】Oracle常用的收集統計資訊方式Oracle
- SAMPLE語句在統計資訊收集中應用
- 收集全庫統計資訊
- mysql如收集統計資訊MySql
- MySQL 5.5 統計資訊收集MySql
- 修改自動收集統計資訊任務的執行時間
- 微課sql最佳化(3)、統計資訊收集(2)-如何收集統計資訊SQL
- MySQL系統如何收集統計資訊MySql
- Oracle 12c資料庫優化器統計資訊收集的最佳實踐(三)|何時不需要收集統計資訊Oracle資料庫優化
- Oracle統計資訊自動收集Oracle
- oracle收集統計資訊job停止Oracle
- 資料庫遷移後的統計資訊更新資料庫
- Oracle10g 資料匯入及index建立 - 統計資訊收集OracleIndex
- Oracle 12c資料庫最佳化器統計資訊收集的最佳實踐(三)|何時不需要收集統計資訊Oracle資料庫
- 大資料量資料遷移後統計資訊問題大資料
- Oracle 11g 修改表級別的自動收集統計資訊比率Oracle
- EBS系統資料庫統計資訊收集總結- gather_schema_stats [final]資料庫
- oracle 統計資訊檢視與收集Oracle
- Fixed Objects Statistics統計資訊收集 - 2Object
- oracle 11g統計資訊收集Oracle
- EMD_MAINTENANCE 引起統計資訊收集AINaN
- 收集統計資訊的簡單操作
- ORACLE 統計資訊的收集與管理Oracle
- 統計資訊收集不完的解決
- 修改oracle 的統計資訊Oracle
- Oracle11g 統計資訊-----統計資訊自動收集任務Oracle
- Oracle11g 統計資訊——統計資訊自動收集任務Oracle
- DB2_收集表統計資料DB2
- 系統日誌及資料庫相關資訊收集資料庫
- UNIX下收集作業系統統計資料作業系統
- Oracle運維指令碼-收集統計資訊Oracle運維指令碼