[20120319]一條sql語句的優化.txt
前天檢查資料庫,發現一天sql語句執行如下:
SELECT MAX (undrug_code) FROM undrug_info WHERE SUBSTR (undrug_code, 1, 1) = 'F';
undrug_code是表undrug_info的主鍵.開始看見這個語句,感覺這樣寫不好,我想像的執行計劃,全掃描索引,然後sort aggregate,找到最大值.
不如這樣寫:
SELECT MAX (undrug_code) FROM undrug_info WHERE undrug_code like 'F%';
對比兩個執行計劃,發現前面的語句邏輯讀更少.僅僅20個邏輯讀,而第2個語句邏輯讀23個.
--可以發現,第1個執行計劃走的是 INDEX FULL SCAN (MIN/MAX),很明顯第1個執行計劃邏輯讀的數量取決於掃描索引的undrug_code的最大值到出現
滿足SUBSTR (undrug_code, 1,1) = 'F'的鍵值停止的塊數.而第2個執行計劃走的是INDEX RANGE SCAN,邏輯讀的數量取決於掃描索引的undrug_code
like 'F%'滿足此條件的塊數.
知道這些,加上取最大值的語句有一些特殊,根據以上分析,如果語句修改如下就能減少邏輯讀:
SELECT MAX (undrug_code) FROM undrug_info WHERE SUBSTR (undrug_code, 1, 1) = 'F';
undrug_code是表undrug_info的主鍵.開始看見這個語句,感覺這樣寫不好,我想像的執行計劃,全掃描索引,然後sort aggregate,找到最大值.
不如這樣寫:
SELECT MAX (undrug_code) FROM undrug_info WHERE undrug_code like 'F%';
對比兩個執行計劃,發現前面的語句邏輯讀更少.僅僅20個邏輯讀,而第2個語句邏輯讀23個.
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID akhuqz90jahvq, child number 0
-------------------------------------
SELECT MAX (undrug_code) FROM undrug_info WHERE SUBSTR (undrug_code, 1,1) = 'F'
Plan hash value: 1995159169
---------------------------------------------------------------
| Id | Operation | Name | E-Rows |
---------------------------------------------------------------
| 1 | SORT AGGREGATE | | 1 |
| 2 | FIRST ROW | | 234 |
|* 3 | INDEX FULL SCAN (MIN/MAX)| PK_UNDRUG_INFO | 234 |
---------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter(SUBSTR("UNDRUG_CODE",1,1)='F')
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID bpb7sh9xq2rqw, child number 0
-------------------------------------
SELECT MAX (undrug_code) FROM undrug_info WHERE undrug_code like 'F%'
Plan hash value: 4281577230
-----------------------------------------------------
| Id | Operation | Name | E-Rows |
-----------------------------------------------------
| 1 | SORT AGGREGATE | | 1 |
|* 2 | INDEX RANGE SCAN| PK_UNDRUG_INFO | 475 |
-----------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("UNDRUG_CODE" LIKE 'F%')
filter("UNDRUG_CODE" LIKE 'F%')
--可以發現,第1個執行計劃走的是 INDEX FULL SCAN (MIN/MAX),很明顯第1個執行計劃邏輯讀的數量取決於掃描索引的undrug_code的最大值到出現
滿足SUBSTR (undrug_code, 1,1) = 'F'的鍵值停止的塊數.而第2個執行計劃走的是INDEX RANGE SCAN,邏輯讀的數量取決於掃描索引的undrug_code
like 'F%'滿足此條件的塊數.
知道這些,加上取最大值的語句有一些特殊,根據以上分析,如果語句修改如下就能減少邏輯讀:
SELECT MAX (undrug_code) FROM undrug_info WHERE SUBSTR (undrug_code, 1, 1) = 'F' and undrug_code
PLAN_TABLE_OUTPUT-------------------------------------SQL_ID 8ndrgww40s2kc, child number 0-------------------------------------SELECT MAX (undrug_code) FROM undrug_info WHERE SUBSTR (undrug_code,1, 1) = 'F' and undrug_code
Plan hash value: 550870910----------------------------------------------------------------| Id | Operation | Name | E-Rows |----------------------------------------------------------------| 1 | SORT AGGREGATE | | 1 || 2 | FIRST ROW | | 5 ||* 3 | INDEX RANGE SCAN (MIN/MAX)| PK_UNDRUG_INFO | 5 |----------------------------------------------------------------Predicate Information (identified by operation id):---------------------------------------------------3 - access("UNDRUG_CODE"filter(SUBSTR("UNDRUG_CODE",1,1)='F')
或者這樣:SELECT MAX (undrug_code) FROM undrug_info WHERE undrug_code >='F' and undrug_code
PLAN_TABLE_OUTPUT------------------------------------------------------------------------SQL_ID ach8g0ct3r7k0, child number 0-------------------------------------SELECT MAX (undrug_code) FROM undrug_info WHERE undrug_code >='F' and undrug_codePlan hash value: 550870910----------------------------------------------------------------| Id | Operation | Name | E-Rows |----------------------------------------------------------------| 1 | SORT AGGREGATE | | 1 || 2 | FIRST ROW | | 475 ||* 3 | INDEX RANGE SCAN (MIN/MAX)| PK_UNDRUG_INFO | 475 |----------------------------------------------------------------Predicate Information (identified by operation id):---------------------------------------------------3 - access("UNDRUG_CODE"='F')
或者這樣:SELECT MAX (undrug_code) FROM undrug_info WHERE undrug_code >='F' and undrug_code<='F'||chr(255);
PLAN_TABLE_OUTPUT------------------------------------------------------------------------------------SQL_ID 2yjg9nmgb6bt8, child number 0-------------------------------------SELECT MAX (undrug_code) FROM undrug_info WHERE undrug_code >='F' andundrug_code<='F'||chr(255)
Plan hash value: 550870910----------------------------------------------------------------| Id | Operation | Name | E-Rows |----------------------------------------------------------------| 1 | SORT AGGREGATE | | 1 || 2 | FIRST ROW | | 474 ||* 3 | INDEX RANGE SCAN (MIN/MAX)| PK_UNDRUG_INFO | 474 |----------------------------------------------------------------Predicate Information (identified by operation id):---------------------------------------------------3 - access("UNDRUG_CODE"<='F?' AND "UNDRUG_CODE">='F')
不過作為第3方,不能修改語句呢?確實不好做,不過如果是11GR2,可以建立一個函式索引:
CREATE UNIQUE INDEX if_UNDRUG_INFO_undrug_code ON FSHIS.UNDRUG_INFO (substr(undrug_code,1,1),UNDRUG_CODE);
--如果這樣代價有點大!SQL> select * from v$version ;
BANNER--------------------------------------------------------------------------------Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit ProductionPL/SQL Release 11.2.0.1.0 - ProductionCORE 11.2.0.1.0 ProductionTNS for Linux: Version 11.2.0.1.0 - ProductionNLSRTL Version 11.2.0.1.0 - Production
SQL> CREATE TABLE test1 AS SELECT ROWNUM ID ,DBMS_RANDOM.STRING('U',10)||LPAD(ROWNUM,6,0) code ,LPAD('a',60,'a') vc FROM DUAL CONNECT BY LEVEL<=10000;SQL> CREATE UNIQUE INDEX pk_test1 ON TEST1 (CODE) ;SQL> ALTER TABLE TEST1 ADD CONSTRAINT pk_test1 PRIMARY KEY (CODE);
SQL> exec dbms_stats.gather_table_stats(ownname=>USER, tabname=>'test1');
SQL> set autotrace traceSQL> select max(code) from test1 where substr(code,1,1)='F';Execution Plan----------------------------------------------------------Plan hash value: 1164682198
----------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |----------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | 17 | 2 (0)| 00:00:01 || 1 | SORT AGGREGATE | | 1 | 17 | | || 2 | FIRST ROW | | 1 | 17 | 2 (0)| 00:00:01 ||* 3 | INDEX FULL SCAN (MIN/MAX)| PK_TEST1 | 1 | 17 | 2 (0)| 00:00:01 |----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):---------------------------------------------------
3 - filter(SUBSTR("CODE",1,1)='F')Statistics----------------------------------------------------------0 recursive calls0 db block gets31 consistent gets0 physical reads0 redo size541 bytes sent via SQL*Net to client520 bytes received via SQL*Net from client2 SQL*Net roundtrips to/from client0 sorts (memory)0 sorts (disk)1 rows processed
SQL> CREATE UNIQUE INDEX if_test1_code ON TEST1 (substr(code,1,1),CODE) ;Index created.
SQL> select max(code) from test1 where substr(code,1,1)='F';Execution Plan----------------------------------------------------------Plan hash value: 1185817353
----------------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |----------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | 20 | 2 (0)| 00:00:01 || 1 | SORT AGGREGATE | | 1 | 20 | | || 2 | FIRST ROW | | 1 | 20 | 2 (0)| 00:00:01 ||* 3 | INDEX RANGE SCAN (MIN/MAX)| IF_TEST1_CODE | 1 | 20 | 2 (0)| 00:00:01 |----------------------------------------------------------------------------------------------Predicate Information (identified by operation id):---------------------------------------------------3 - access(SUBSTR("CODE",1,1)='F')Statistics----------------------------------------------------------0 recursive calls0 db block gets2 consistent gets0 physical reads0 redo size541 bytes sent via SQL*Net to client520 bytes received via SQL*Net from client2 SQL*Net roundtrips to/from client0 sorts (memory)0 sorts (disk)1 rows processed
--可以發現可以使用函式索引,並且邏輯讀減少.10G,留給大家測試,^_^.
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/267265/viewspace-719135/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 一條sql語句的優化SQL優化
- 一條SQL語句的優化過程SQL優化
- [20181114]一條sql語句的優化.txtSQL優化
- [20131025]一條sql語句的優化.txtSQL優化
- [20151203]一條sql語句的優化.txtSQL優化
- [20150715]一條sql語句的優化.txtSQL優化
- [20130319]一條sql語句的優化.txtSQL優化
- [20151209]一條sql語句的優化(續).txtSQL優化
- [20140210]一條sql語句的優化(11g).txtSQL優化
- SQL語句優化--十條經驗SQL優化
- 一條sql語句優化不出來, 哭了一鼻子SQL優化
- 一條update語句的優化探索優化
- 一個SQL語句的優化SQL優化
- SQL語句的優化SQL優化
- 一條sql語句的建議調優分析SQL
- 一條簡單的SQL語句優化-新年新氣象SQL優化
- SQL語句優化SQL優化
- 總結出10條SQL語句優化精髓SQL優化
- SQL Server優化之SQL語句優化SQLServer優化
- SQL 語句的優化方法SQL優化
- 一次sql語句優化的反思SQL優化
- Mysql 52條SQL語句效能優化策略彙總MySql優化
- 通過_optimizer_rownum_pred_based_fkr優化一條sql語句優化SQL
- [20131204]sql語句優化.txtSQL優化
- [20151221]sql語句優化.txtSQL優化
- MYSQL SQL語句優化MySql優化
- sql語句效能優化SQL優化
- 求助:SQL語句優化SQL優化
- [20170104]一條sql優化.txtSQL優化
- 一條SQL語句的書寫SQL
- 一條很 巧妙的 SQL 語句SQL
- 一條SQL語句的旅行之路SQL
- SQL語句優化的34條建議(轉-浪花七八朵 )SQL優化
- 優化 SQL 語句的步驟優化SQL
- 關於sql語句的優化SQL優化
- sql語句的優化案例分析SQL優化
- [20201210]sql語句優化.txtSQL優化
- MySQL之SQL語句優化MySql優化