【SQL優化】UNION替換OR效率測試及總結
大家在做SQL優化的過程中,可能都知道一個事實:某些情況下使用UNION替換OR可以提高SQL的執行效率。
您知道這個“某些情況”指的是什麼麼?
解釋一下,“某些情況”指的是:使用的表欄位要有索引。
這個實驗,給大家展示一下這個結論
1.建立測試表
sec@ora10g> drop table t;
Table dropped.
sec@ora10g> create table t as select * from all_objects;
Table created.
sec@ora10g> alter table t rename column owner to x;
Table altered.
sec@ora10g> alter table t rename column object_name to y;
Table altered.
sec@ora10g> update t set x = 'secooler';
4785 rows updated.
OK,通過上面的初始化,我們得到了這個測試表T,我們關心它的第一個和第二個欄位,修改名字後是x欄位和y欄位
x欄位內容統一修改為“secooler”,以便模擬使用這個欄位得到大量返回結果
y欄位指定特定值後,模擬返回一條記錄
2.開啟autotrace,跟蹤不同的SQL執行(為使執行計劃穩定,請多次執行,得到穩定輸出結果)
用到的測試SQL語句是以下三條
1)返回記錄多的條件放在where子句的前面
select * from t where x = 'secooler' or y = 'T';
2)返回記錄多的條件放在where子句的後面
select * from t where y = 'T' or x = 'secooler';
3)使用UNION改寫上面的OR語句
select * from t where x = 'secooler'
union
select * from t where y = 'T'
/
3.先看一下,在沒有建立索引情況下的實驗效果
sec@ora10g> set autotrace traceonly
sec@ora10g> select * from t where x = 'secooler' or y = 'T';
4782 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 1601196873
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4583 | 572K| 16 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| T | 4583 | 572K| 16 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("X"='secooler' OR "Y"='T')
Note
-----
- dynamic sampling used for this statement
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
111 consistent gets
0 physical reads
0 redo size
206142 bytes sent via SQL*Net to client
1009 bytes received via SQL*Net from client
49 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
4782 rows processed
sec@ora10g> select * from t where y = 'T' or x = 'secooler';
4782 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 1601196873
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4583 | 572K| 16 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| T | 4583 | 572K| 16 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("Y"='T' OR "X"='secooler')
Note
-----
- dynamic sampling used for this statement
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
111 consistent gets
0 physical reads
0 redo size
206142 bytes sent via SQL*Net to client
1009 bytes received via SQL*Net from client
49 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
4782 rows processed
sec@ora10g> select * from t where x = 'secooler'
union
select * from t where y = 'T'
/
2 3 4
4782 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 2618920678
------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4584 | 573K| | 168 (12)| 00:00:03 |
| 1 | SORT UNIQUE | | 4584 | 573K| 1448K| 168 (12)| 00:00:03 |
| 2 | UNION-ALL | | | | | | |
|* 3 | TABLE ACCESS FULL| T | 4583 | 572K| | 16 (0)| 00:00:01 |
|* 4 | TABLE ACCESS FULL| T | 1 | 128 | | 16 (0)| 00:00:01 |
------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter("X"='secooler')
4 - filter("Y"='T')
Note
-----
- dynamic sampling used for this statement
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
126 consistent gets
0 physical reads
0 redo size
253890 bytes sent via SQL*Net to client
1009 bytes received via SQL*Net from client
49 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
4782 rows processed
4.在沒有建立索引情況下的實驗結論
1)無論是返回記錄多的條件放在where子句的前面還是後面,從執行計劃上看,效率是一樣的。
2)沒有建立索引的情況下,使用UNION改寫後效率沒有提高,反而下降了
5.在看一下,建立所需的索引情況後的實驗效果
sec@ora10g> create index idx1_t on t(x);
Index created.
sec@ora10g> create index idx2_t on t(y);
Index created.
sec@ora10g> select * from t where x = 'secooler' or y = 'T';
4782 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 1601196873
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4583 | 572K| 16 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| T | 4583 | 572K| 16 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("X"='secooler' OR "Y"='T')
Note
-----
- dynamic sampling used for this statement
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
111 consistent gets
0 physical reads
0 redo size
206142 bytes sent via SQL*Net to client
1009 bytes received via SQL*Net from client
49 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
4782 rows processed
sec@ora10g> select * from t where y = 'T' or x = 'secooler';
4782 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 1601196873
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4583 | 572K| 16 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| T | 4583 | 572K| 16 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("Y"='T' OR "X"='secooler')
Note
-----
- dynamic sampling used for this statement
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
111 consistent gets
0 physical reads
0 redo size
206142 bytes sent via SQL*Net to client
1009 bytes received via SQL*Net from client
49 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
4782 rows processed
sec@ora10g> select * from t where x = 'secooler'
union
select * from t where y = 'T'
/
2 3 4
4782 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 4276936497
------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4584 | 573K| | 153 (3)| 00:00:02 |
| 1 | SORT UNIQUE | | 4584 | 573K| 1448K| 153 (3)| 00:00:02 |
| 2 | UNION-ALL | | | | | | |
|* 3 | TABLE ACCESS FULL | T | 4583 | 572K| | 16 (0)| 00:00:01 |
| 4 | TABLE ACCESS BY INDEX ROWID| T | 1 | 128 | | 2 (0)| 00:00:01 |
|* 5 | INDEX RANGE SCAN | IDX2_T | 1 | | | 1 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter("X"='secooler')
5 - access("Y"='T')
Note
-----
- dynamic sampling used for this statement
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
66 consistent gets
0 physical reads
0 redo size
253890 bytes sent via SQL*Net to client
1009 bytes received via SQL*Net from client
49 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
4782 rows processed
6.在建立所需的索引後的實驗結果
1)無論是返回記錄多的條件放在where子句的前面還是後面,從執行計劃上看,效率還是一樣的。
2)從“consistent gets”引數上看,使用UNION改寫OR後,效率得到有效的提升。
7.小結
通過上面的實驗,可以得到在CBO模式下,無論是返回記錄多的條件放在where子句的前面還是後面,從執行計劃上看,效率是一樣的。
另外一個重要結論就是:在考慮使用UNION改寫OR的時候,一定要注意檢視使用的欄位是否已經建立了索引。
Goodluck.
-- The End --
您知道這個“某些情況”指的是什麼麼?
解釋一下,“某些情況”指的是:使用的表欄位要有索引。
這個實驗,給大家展示一下這個結論
1.建立測試表
sec@ora10g> drop table t;
Table dropped.
sec@ora10g> create table t as select * from all_objects;
Table created.
sec@ora10g> alter table t rename column owner to x;
Table altered.
sec@ora10g> alter table t rename column object_name to y;
Table altered.
sec@ora10g> update t set x = 'secooler';
4785 rows updated.
OK,通過上面的初始化,我們得到了這個測試表T,我們關心它的第一個和第二個欄位,修改名字後是x欄位和y欄位
x欄位內容統一修改為“secooler”,以便模擬使用這個欄位得到大量返回結果
y欄位指定特定值後,模擬返回一條記錄
2.開啟autotrace,跟蹤不同的SQL執行(為使執行計劃穩定,請多次執行,得到穩定輸出結果)
用到的測試SQL語句是以下三條
1)返回記錄多的條件放在where子句的前面
select * from t where x = 'secooler' or y = 'T';
2)返回記錄多的條件放在where子句的後面
select * from t where y = 'T' or x = 'secooler';
3)使用UNION改寫上面的OR語句
select * from t where x = 'secooler'
union
select * from t where y = 'T'
/
3.先看一下,在沒有建立索引情況下的實驗效果
sec@ora10g> set autotrace traceonly
sec@ora10g> select * from t where x = 'secooler' or y = 'T';
4782 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 1601196873
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4583 | 572K| 16 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| T | 4583 | 572K| 16 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("X"='secooler' OR "Y"='T')
Note
-----
- dynamic sampling used for this statement
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
111 consistent gets
0 physical reads
0 redo size
206142 bytes sent via SQL*Net to client
1009 bytes received via SQL*Net from client
49 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
4782 rows processed
sec@ora10g> select * from t where y = 'T' or x = 'secooler';
4782 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 1601196873
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4583 | 572K| 16 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| T | 4583 | 572K| 16 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("Y"='T' OR "X"='secooler')
Note
-----
- dynamic sampling used for this statement
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
111 consistent gets
0 physical reads
0 redo size
206142 bytes sent via SQL*Net to client
1009 bytes received via SQL*Net from client
49 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
4782 rows processed
sec@ora10g> select * from t where x = 'secooler'
union
select * from t where y = 'T'
/
2 3 4
4782 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 2618920678
------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4584 | 573K| | 168 (12)| 00:00:03 |
| 1 | SORT UNIQUE | | 4584 | 573K| 1448K| 168 (12)| 00:00:03 |
| 2 | UNION-ALL | | | | | | |
|* 3 | TABLE ACCESS FULL| T | 4583 | 572K| | 16 (0)| 00:00:01 |
|* 4 | TABLE ACCESS FULL| T | 1 | 128 | | 16 (0)| 00:00:01 |
------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter("X"='secooler')
4 - filter("Y"='T')
Note
-----
- dynamic sampling used for this statement
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
126 consistent gets
0 physical reads
0 redo size
253890 bytes sent via SQL*Net to client
1009 bytes received via SQL*Net from client
49 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
4782 rows processed
4.在沒有建立索引情況下的實驗結論
1)無論是返回記錄多的條件放在where子句的前面還是後面,從執行計劃上看,效率是一樣的。
2)沒有建立索引的情況下,使用UNION改寫後效率沒有提高,反而下降了
5.在看一下,建立所需的索引情況後的實驗效果
sec@ora10g> create index idx1_t on t(x);
Index created.
sec@ora10g> create index idx2_t on t(y);
Index created.
sec@ora10g> select * from t where x = 'secooler' or y = 'T';
4782 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 1601196873
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4583 | 572K| 16 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| T | 4583 | 572K| 16 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("X"='secooler' OR "Y"='T')
Note
-----
- dynamic sampling used for this statement
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
111 consistent gets
0 physical reads
0 redo size
206142 bytes sent via SQL*Net to client
1009 bytes received via SQL*Net from client
49 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
4782 rows processed
sec@ora10g> select * from t where y = 'T' or x = 'secooler';
4782 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 1601196873
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4583 | 572K| 16 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| T | 4583 | 572K| 16 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("Y"='T' OR "X"='secooler')
Note
-----
- dynamic sampling used for this statement
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
111 consistent gets
0 physical reads
0 redo size
206142 bytes sent via SQL*Net to client
1009 bytes received via SQL*Net from client
49 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
4782 rows processed
sec@ora10g> select * from t where x = 'secooler'
union
select * from t where y = 'T'
/
2 3 4
4782 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 4276936497
------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4584 | 573K| | 153 (3)| 00:00:02 |
| 1 | SORT UNIQUE | | 4584 | 573K| 1448K| 153 (3)| 00:00:02 |
| 2 | UNION-ALL | | | | | | |
|* 3 | TABLE ACCESS FULL | T | 4583 | 572K| | 16 (0)| 00:00:01 |
| 4 | TABLE ACCESS BY INDEX ROWID| T | 1 | 128 | | 2 (0)| 00:00:01 |
|* 5 | INDEX RANGE SCAN | IDX2_T | 1 | | | 1 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter("X"='secooler')
5 - access("Y"='T')
Note
-----
- dynamic sampling used for this statement
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
66 consistent gets
0 physical reads
0 redo size
253890 bytes sent via SQL*Net to client
1009 bytes received via SQL*Net from client
49 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
4782 rows processed
6.在建立所需的索引後的實驗結果
1)無論是返回記錄多的條件放在where子句的前面還是後面,從執行計劃上看,效率還是一樣的。
2)從“consistent gets”引數上看,使用UNION改寫OR後,效率得到有效的提升。
7.小結
通過上面的實驗,可以得到在CBO模式下,無論是返回記錄多的條件放在where子句的前面還是後面,從執行計劃上看,效率是一樣的。
另外一個重要結論就是:在考慮使用UNION改寫OR的時候,一定要注意檢視使用的欄位是否已經建立了索引。
Goodluck.
-- The End --
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/519536/viewspace-615470/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 【SQL最佳化】UNION替換OR效率測試及總結SQL
- sql 優化過程之union 替換 orSQL優化
- UNION效率比UNION ALL效率高——SQL優化之Everything is possibleSQL優化
- 【轉】UNION效率比UNION ALL效率高——SQL優化之Everything is possibleSQL優化
- SQL優化案例-union代替or(九)SQL優化
- SQL優化思路&結果集重用優化、分割槽索引優化測試SQL優化索引
- unity替換mesh測試Unity
- Oracle SQL優化總結OracleSQL優化
- Oracle SQL優化 總結OracleSQL優化
- Oracle SQL語句優化之UNIONOracleSQL優化
- MySQL的SQL效能優化總結MySql優化
- union 優化方法優化
- 【OracleSQL】常用自動替換總結OracleSQL
- IP替換的IPAT的接管測試
- 前端單元測試總結及測試工具介紹前端
- SQL Server 替換SQLServer
- 自動化測試總結(二)
- SQL 優化經驗總結34條SQL優化
- SQL優化經驗總結34條SQL優化
- 總結SQL語句中的優化提示SQL優化
- MySQL 索引及查詢優化總結MySql索引優化
- 一次效能測試調優總結
- python測試request代理IP是否替換Python
- Oracle SQL效能優化技巧大總結_水OracleSQL優化
- SQL優化經驗總結34條(一)SQL優化
- SQL優化經驗總結34條(二)SQL優化
- 自動化測試實踐總結
- 測試總結①
- 引入測試報告與結構優化(二)測試套件測試報告優化套件
- 【OC梳理】效能檢測及優化彙總優化
- SQL精華總結索引型別優化SQL優化事務大表優化思維導圖❤️SQL索引型別優化
- run_stats---sql效率測試工具(轉)SQL
- RecyclerView 體驗優化及入坑總結View優化
- 單元測試效率優化:為什麼要對程式進行測試?測試有什麼好處?優化
- 總結出10條SQL語句優化精髓SQL優化
- Pytest單元測試框架生成HTML測試報告及優化框架HTML測試報告優化
- APP UI自動化測試思路總結APPUI
- 介面自動化測試框架搭建總結框架