高效的SQL( clustering factor減少COST)
高效的SQL( clustering factor減少COST)
1、建立樣表cluster_factor(x有序列,y隨意列);實驗表cluster01(low)、cluster02(high)
doudou@TEST> create table cluster_factor (x int, y int);
Table created.
doudou@TEST> begin
2 for i in 1..1000000 loop
3 insert into cluster_factor values (i,to_char(dbms_random.random,'9999999999999999'));
4 end loop;
5 commit;
6 end;
7 /
PL/SQL procedure successfully completed.
cluster01表
doudou@TEST> create table cluster01 as select * from cluster_factor;
Table created.
cluster02表
doudou@TEST> create table cluster02 as select * from cluster_factor order by y;
Table created.
index_cluster01索引(索引列有序)
doudou@TEST> create index index_cluster01 on cluster01(x);
Index created.
index_cluster02索引(索引列無序)
doudou@TEST> create index index_cluster02 on cluster02(x);
Index created.
利用dbms_stats收集表的索引資訊 (cascade是否收集索引資訊選項)
doudou@TEST> begin
2 dbms_stats.gather_table_stats(user,'cluster01',cascade=>true);
3 dbms_stats.gather_table_stats(user,'cluster02',cascade=>true);
4 end;
5 /
PL/SQL procedure successfully completed.
或
doudou@TEST> exec dbms_stats.gather_table_stats('DOUDOU','cluster01',cascade=>true);
PL/SQL procedure successfully completed.
doudou@TEST> exec dbms_stats.gather_table_stats('DOUDOU','cluster02',cascade=>true);
PL/SQL procedure successfully completed.
2、開啟執行計劃並查詢SQL
doudou@TEST> set autot on
doudou@TEST> select avg(y/(x+1)) from cluster01 where x between 10000 and 30000;
AVG(Y/(X+1))
------------
-369.65884
Execution Plan
----------------------------------------------------------
Plan hash value: 3265002277
------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 12 | 143 (0)| 00:00:02 |
| 1 | SORT AGGREGATE | | 1 | 12 | | |
| 2 | TABLE ACCESS BY INDEX ROWID| CLUSTER01 | 20144 | 236K| 143 (0)| 00:00:02 |
|* 3 | INDEX RANGE SCAN | INDEX_CLUSTER01 | 20144 | | 47 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("X">=10000 AND "X"<=30000)
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
116 consistent gets
60 physical reads
0 redo size
434 bytes sent via SQL*Net to client
400 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
doudou@TEST> select avg(y/(x+1)) from cluster02 where x between 10000 and 30000;
AVG(Y/(X+1))
------------
-369.65884
Execution Plan
----------------------------------------------------------
Plan hash value: 2721670139
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 12 | 542 (1)| 00:00:07 |
| 1 | SORT AGGREGATE | | 1 | 12 | | |
|* 2 | TABLE ACCESS FULL| CLUSTER02 | 20130 | 235K| 542 (1)| 00:00:07 |
--------------------------------------------------------------------------------
【問題1:2個表的資料、索引都是一樣的。為什麼cluster01走索引,而cluster02全表掃描呢?】
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("X"<=30000 AND "X">=10000)
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
2417 consistent gets
2411 physical reads
0 redo size
434 bytes sent via SQL*Net to client
400 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
doudou@TEST> SELECT /*+ INDEX(CLUSTER02 INDEX_CLUSTER02)*/AVG(Y/(X+1)) FROM CLUSTER02 WHERE X BETWEEN 10000 AND 30000;
AVG(Y/(X+1))
------------
-369.65884
Execution Plan
----------------------------------------------------------
Plan hash value: 924486639
------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 12 | 20171 (1)| 00:04:03 |
| 1 | SORT AGGREGATE | | 1 | 12 | | |
| 2 | TABLE ACCESS BY INDEX ROWID| CLUSTER02 | 20130 | 235K| 20171 (1)| 00:04:03 |
|* 3 | INDEX RANGE SCAN | INDEX_CLUSTER02 | 20130 | | 47 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------
【問題2:強制cluster02走索引,但是最後cost消耗還是很大】
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("X">=10000 AND "X"<=30000)
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
20040 consistent gets
0 physical reads
0 redo size
434 bytes sent via SQL*Net to client
400 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
doudou@TEST> select
2 idx.index_name,
3 tab.table_name,
4 tab.num_rows,
5 tab.blocks,
6 idx.clustering_factor
7 from
8 user_indexes idx inner join user_tables tab
9 on idx.table_name = tab.table_name
10 order by table_name;
INDEX_NAME TABLE_NAME NUM_ROWS BLOCKS CLUSTERING_FACTOR
------------------------------ ------------------------------ ---------- ---------- -----------------
INDEX_CLUSTER01 CLUSTER01 1006949 2459 4726
INDEX_CLUSTER02 CLUSTER02 1006232 2459 999628
【cluster01與cluster02的clustering factor不同,發現了問題1的答案;
問題1的答案:物理分佈的不同導致了索引的選擇
問題2的答案:強制走索引不是適合所有的操作,有時也會造成更大的cost消耗
(clustering factor 高,相鄰索引值指向更多不同的塊,本來一個塊可以返回的資訊卻需要資料庫去讀更多的塊,而這裡又強制使用rowid全表掃描所以造成了更多的cost)】
3、總結:
low的clustering factor減少了對相同塊的重複讀,從而減少cost的消耗,
high的clustering factor增加了對相同塊的重複讀,從而增加cost的消耗。
後語:建立表按照一定的順序是有必要的,這樣可以減低clustering factor(或者可以說索引建在有序的列上效能會好一些),從而優化sql
4、附表:指令碼
1、檢視clustering_factoer
idx.index_name,
tab.table_name,
tab.num_rows,
tab.blocks,
idx.clustering_factor
from
user_indexes idx inner join user_tables tab
on idx.table_name = tab.table_name
order by table_name;
2、收集資訊
dbms_stats 與 analyze
dbms_stats注意:1、不可以收集叢集資訊,但可以收集單獨表來代替收集整個叢集。
2、收集優化器統計優先考慮
analyze注意:1、use the VALIDATE or LIST CHAINED ROWS clauses、collect information on free list blocks
2、收集優化器統計不優先考慮
總結:Oracle推薦收集優化器統計使用dbms_stats
Note:
Do not use the COMPUTE and ESTIMATE clauses of ANALYZE statement to collect optimizer statistics. These clauses are supported solely for backward compatibility and may be removed in a future release. The DBMS_STATS package collects a broader, more accurate set of statistics, and gathers statistics more efficiently.
You may continue to use ANALYZE statement to for other purposes not related to optimizer statistics collection:
To use the VALIDATE or LIST CHAINED ROWS clauses
To collect information on free list blocks
Statistics Gathering Procedures in the DBMS_STATS Package
Procedure |
Collects |
Index statistics |
|
Table, column, and index statistics |
|
Statistics for all objects in a schema |
|
Statistics for all dictionary objects |
|
Statistics for all objects in a database |
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/26442936/viewspace-750901/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- [Oracle] Clustering FactorOracle
- oracle的clustering_factorOracle
- Clustering Factor——索引的成本指標索引指標
- 關於索引聚簇因子(CLUSTERING_FACTOR)引起的sql優化過程索引SQL優化
- DBA_INDEXES.CLUSTERING_FACTOR 索引的群集因子初探Index索引
- 減少SQL Server死鎖的方法SQLServer
- 高效的SQL語句有助於減少資料庫的訪問次數SQL資料庫
- CLUSTERING_FACTOR影響執行計劃
- DBA_INDEXES.CLUSTERING_FACTOR 索引的群集因子初探(原)Index索引
- 13_共享SQL減少硬解析SQL
- 減少SQL日誌的三種方法(轉)SQL
- 淺談索引系列之聚簇因子(clustering_factor)索引
- clustering factor索引聚簇因子和執行計劃索引
- 11g 是否有解決clustering_factor 高的問題
- 高效能web建站規則(儘量減少http請求)WebHTTP
- oracle sql tuning 5--避免防範或者減少問題SQLOracleSQL
- 使用MVVM減少控制器程式碼實戰(減少56%)MVVM
- 減少對錶的查詢
- javascript提高效能方式之減少dom元素訪問次數JavaScript
- SQL 語句調優_減少或者避免笛卡爾乘積的發生SQL
- 減少該死的 if else 巢狀巢狀
- 減少oracle日誌的產生Oracle
- CLUSTERING_FACTOR、回表、資料分佈傾斜走全表還是索引索引
- laravel欄位減少增加Laravel
- 減少apk包大小的一種思路APK
- LVM管理之減少LV的大小LVM
- 減少ORACLE中的磁碟I/O(轉)Oracle
- tcp減少2msl的時間TCP
- face 31減少http請求HTTP
- 如何減少同事工作變動
- 使用rownum減少函式呼叫函式
- 如何減少 Hyperf 框架的掃描時間框架
- [譯] 減少 Python 中迴圈的使用Python
- 前端頁面優化,減少 reflow 的方法前端優化
- python爬蟲如何減少ip的限制Python爬蟲
- 減少Android APK的大小99.99%AndroidAPK
- 安卓手機減少流量的4個技巧安卓
- 圖靈社群減少的功能(20170517)圖靈