【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/29065182/viewspace-1156624/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- SQL最佳化案例-union代替or(九)SQL
- SQL Server 替換SQLServer
- 【OracleSQL】常用自動替換總結OracleSQL
- python測試request代理IP是否替換Python
- run_stats---sql效率測試工具(轉)SQL
- 測試總結①
- 網際網路App應用程式測試流程及測試總結APP
- kingbase SQL最佳化案例 ( union遞迴 改 cte遞迴 )SQL遞迴
- sql中union和union all的用法SQL
- 測試流程總結
- 【JUnit測試】總結
- 微課sql最佳化(17)、不改程式碼,最佳化SQL(1)-最佳化方法總結SQL
- 測試面試題總結面試題
- 行情壓測效能最佳化總結
- sql中UNION和UNION ALL的區別SQL
- SQL語句替換查詢結果的的寫法舉例SQL
- SQL中的替換函式replace()使用SQL函式
- 軟體測試要學什麼(4)軟體測試流程及常見測試點總結
- 功能測試點總結
- 測試總結報告
- APP黑盒測試總結APP
- web測試方法總結Web
- 作業測試總結
- 測試入門總結
- union all 最佳化案例
- sql注入之union注入SQL
- 初識效能測試(測試小白麵試總結)
- 從測試小白到測試組長,談談我的測試過程及管理經驗總結
- sql 正則替換資料庫語句!SQL資料庫
- 測試merge效率
- 滲透測試技巧總結
- APP 安全測試項總結APP
- 測試工程師的面試總結工程師面試
- Mybatis(一)Porxy動態代理和sql解析替換MyBatisSQL
- mysql使用phpmyadmin批次替換資料sql語句MySqlPHP
- 手工測試與APPSCAN自動化測試結合的提高效率測試策略APP
- 轉:測試工程師的面試總結工程師面試
- HTML 替換元素與非替換元素HTML
- 測試功能點總結摘要1