前兩天同事問我這個問題,估計不少人都不清楚,順便寫出來。
Oracle的HINT能夠強制指定SQL的執行計劃,好比選擇索引、表的鏈接順序以及表的鏈接方式等等。
不過若是查詢的是視圖,使用HINT就變得麻煩一些。
看一個具體的例子吧:
SQL> CREATE TABLE T1 (ID NUMBER, NAME VARCHAR2(30), TYPE VARCHAR2(30));
表已建立。
SQL> CREATE TABLE T2 (ID NUMBER, NAME VARCHAR2(30), TYPE VARCHAR2(30));
表已建立。
SQL> CREATE INDEX IND_T1_NAME ON T1 (NAME);
索引已建立。
SQL> CREATE INDEX IND_T2_NAME ON T2 (NAME);
索引已建立。
SQL> INSERT INTO T1 SELECT ROWNUM, OBJECT_NAME, OBJECT_TYPE
FROM DBA_OBJECTS WHERE OBJECT_TYPE = 'TABLE';
已建立2058行。
SQL> INSERT INTO T2 SELECT ROWNUM, OBJECT_NAME, OBJECT_TYPE
FROM DBA_OBJECTS WHERE OBJECT_TYPE = 'TABLE';
已建立2058行。
SQL> COMMIT;
提交完成。
SQL> CREATE VIEW V_T AS
SELECT * FROM T1 UNION ALL SELECT * FROM T2;
視圖已建立。
建立了一個包含UNION ALL查詢的視圖,下面執行對這個視圖的查詢:
SQL> SET AUTOT ON EXP
SQL> SELECT *
FROM V_T WHERE NAME LIKE 'B%';
ID NAME TYPE
---------- ------------------------------ ------------------------------
13 BOOTSTRAP$ TABLE
1774 BONUS TABLE
1871 BS TABLE
1872 BP TABLE
1873 BCF TABLE
1876 BSF TABLE
1877 BDF TABLE
1880 BRL TABLE
1881 BCB TABLE
13 BOOTSTRAP$ TABLE
1774 BONUS TABLE
1871 BS TABLE
1872 BP TABLE
1873 BCF TABLE
1876 BSF TABLE
1877 BDF TABLE
1880 BRL TABLE
1881 BCB TABLE
已選擇18行。
執行計劃
----------------------------------------------------------
Plan hash value: 2128801320
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 55 | 2585 | 2 (0)| 00:00:01 |
| 1 | VIEW | V_T | 55 | 2585 | 2 (0)| 00:00:01 |
| 2 | UNION-ALL PARTITION| | | | | |
|* 3 | TABLE ACCESS FULL | T1 | 9 | 423 | 5 (0)| 00:00:01 |
|* 4 | TABLE ACCESS FULL | T2 | 9 | 423 | 5 (0)| 00:00:01 |
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter("NAME" LIKE 'B%')
4 - filter("NAME" LIKE 'B%')
Note
-----
- dynamic sampling used for this statement
能夠看到,Oracle沒有使用索引,對於這個SQL來講,若是T1和T2都使用索引掃描的話,效率會更高,
可是,對於包含視圖的查詢,普通的HINT指定方法是無效的:
SQL> SELECT /*+ INDEX(T1 IND_T1_NAME) */ *
FROM V_T WHERE NAME LIKE 'B%';
ID NAME TYPE
---------- ------------------------------ ------------------------------
13 BOOTSTRAP$ TABLE
1774 BONUS TABLE
1871 BS TABLE
1872 BP TABLE
1873 BCF TABLE
1876 BSF TABLE
1877 BDF TABLE
1880 BRL TABLE
1881 BCB TABLE
13 BOOTSTRAP$ TABLE
1774 BONUS TABLE
1871 BS TABLE
1872 BP TABLE
1873 BCF TABLE
1876 BSF TABLE
1877 BDF TABLE
1880 BRL TABLE
1881 BCB TABLE
已選擇18行。
執行計劃
----------------------------------------------------------
Plan hash value: 2128801320
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 55 | 2585 | 2 (0)| 00:00:01 |
| 1 | VIEW | V_T | 55 | 2585 | 2 (0)| 00:00:01 |
| 2 | UNION-ALL PARTITION| | | | | |
|* 3 | TABLE ACCESS FULL | T1 | 9 | 423 | 5 (0)| 00:00:01 |
|* 4 | TABLE ACCESS FULL | T2 | 9 | 423 | 5 (0)| 00:00:01 |
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter("NAME" LIKE 'B%')
4 - filter("NAME" LIKE 'B%')
Note
-----
- dynamic sampling used for this statement
其實指定HINT的方法並不複雜,只須要指定VIEW的名稱做爲表名的前綴就能夠了:
SQL> SELECT /*+ INDEX(V_T.T1 IND_T1_NAME) */ *
FROM V_T WHERE NAME LIKE 'B%';
ID NAME TYPE
---------- ------------------------------ ------------------------------
1881 BCB TABLE
1873 BCF TABLE
1877 BDF TABLE
1774 BONUS TABLE
13 BOOTSTRAP$ TABLE
1872 BP TABLE
1880 BRL TABLE
1871 BS TABLE
1876 BSF TABLE
13 BOOTSTRAP$ TABLE
1774 BONUS TABLE
1871 BS TABLE
1872 BP TABLE
1873 BCF TABLE
1876 BSF TABLE
1877 BDF TABLE
1880 BRL TABLE
1881 BCB TABLE
已選擇18行。
執行計劃
----------------------------------------------------------
Plan hash value: 1398832356
--------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 55 | 2585 | 2 (0)| 00:00:01 |
| 1 | VIEW | V_T | 55 | 2585 | 2 (0)| 00:00:01 |
| 2 | UNION-ALL PARTITION | | | | | |
| 3 | TABLE ACCESS BY INDEX ROWID| T1 | 9 | 423 | 6 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | IND_T1_NAME | 9 | | 2 (0)| 00:00:01 |
|* 5 | TABLE ACCESS FULL | T2 | 9 | 423 | 5 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("NAME" LIKE 'B%')
filter("NAME" LIKE 'B%')
5 - filter("NAME" LIKE 'B%')
Note
-----
- dynamic sampling used for this statement
一樣對於T2表也能夠採用一樣的方法:
SQL> SELECT /*+ INDEX(V_T.T1 IND_T1_NAME) INDEX(V_T.T2 IND_T2_NAME) */ *
FROM V_T WHERE NAME LIKE 'B%';
ID NAME TYPE
---------- ------------------------------ ------------------------------
1881 BCB TABLE
1873 BCF TABLE
1877 BDF TABLE
1774 BONUS TABLE
13 BOOTSTRAP$ TABLE
1872 BP TABLE
1880 BRL TABLE
1871 BS TABLE
1876 BSF TABLE
1881 BCB TABLE
1873 BCF TABLE
1877 BDF TABLE
1774 BONUS TABLE
13 BOOTSTRAP$ TABLE
1872 BP TABLE
1880 BRL TABLE
1871 BS TABLE
1876 BSF TABLE
已選擇18行。
執行計劃
----------------------------------------------------------
Plan hash value: 4053622206
--------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 55 | 2585 | 2 (0)| 00:00:01 |
| 1 | VIEW | V_T | 55 | 2585 | 2 (0)| 00:00:01 |
| 2 | UNION-ALL PARTITION | | | | | |
| 3 | TABLE ACCESS BY INDEX ROWID| T1 | 9 | 423 | 6 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | IND_T1_NAME | 9 | | 2 (0)| 00:00:01 |
| 5 | TABLE ACCESS BY INDEX ROWID| T2 | 9 | 423 | 6 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | IND_T2_NAME | 9 | | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("NAME" LIKE 'B%')
filter("NAME" LIKE 'B%')
6 - access("NAME" LIKE 'B%')
filter("NAME" LIKE 'B%')
Note
-----
- dynamic sampling used for this statement
若是視圖中使用了別名,那麼HINT中指定的時候也要使用別名:
SQL> CREATE OR REPLACE VIEW V_T AS
SELECT * FROM T1 A UNION ALL SELECT * FROM T2 B;
視圖已建立。
SQL> SELECT /*+ INDEX(V_T.T1 IND_T1_NAME) INDEX(V_T.T2 IND_T2_NAME) */ *
FROM V_T WHERE NAME LIKE 'B%';
ID NAME TYPE
---------- ------------------------------ ------------------------------
13 BOOTSTRAP$ TABLE
1774 BONUS TABLE
1871 BS TABLE
1872 BP TABLE
1873 BCF TABLE
1876 BSF TABLE
1877 BDF TABLE
1880 BRL TABLE
1881 BCB TABLE
13 BOOTSTRAP$ TABLE
1774 BONUS TABLE
1871 BS TABLE
1872 BP TABLE
1873 BCF TABLE
1876 BSF TABLE
1877 BDF TABLE
1880 BRL TABLE
1881 BCB TABLE
已選擇18行。
執行計劃
----------------------------------------------------------
Plan hash value: 2128801320
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 55 | 2585 | 2 (0)| 00:00:01 |
| 1 | VIEW | V_T | 55 | 2585 | 2 (0)| 00:00:01 |
| 2 | UNION-ALL PARTITION| | | | | |
|* 3 | TABLE ACCESS FULL | T1 | 9 | 423 | 5 (0)| 00:00:01 |
|* 4 | TABLE ACCESS FULL | T2 | 9 | 423 | 5 (0)| 00:00:01 |
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter("NAME" LIKE 'B%')
4 - filter("NAME" LIKE 'B%')
Note
-----
- dynamic sampling used for this statement
SQL> SELECT /*+ INDEX(V_T.A IND_T1_NAME) INDEX(V_T.B IND_T2_NAME) */ *
FROM V_T WHERE NAME LIKE 'B%';
ID NAME TYPE
---------- ------------------------------ ------------------------------
1881 BCB TABLE
1873 BCF TABLE
1877 BDF TABLE
1774 BONUS TABLE
13 BOOTSTRAP$ TABLE
1872 BP TABLE
1880 BRL TABLE
1871 BS TABLE
1876 BSF TABLE
1881 BCB TABLE
1873 BCF TABLE
1877 BDF TABLE
1774 BONUS TABLE
13 BOOTSTRAP$ TABLE
1872 BP TABLE
1880 BRL TABLE
1871 BS TABLE
1876 BSF TABLE
已選擇18行。
執行計劃
----------------------------------------------------------
Plan hash value: 4053622206
--------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 55 | 2585 | 2 (0)| 00:00:01 |
| 1 | VIEW | V_T | 55 | 2585 | 2 (0)| 00:00:01 |
| 2 | UNION-ALL PARTITION | | | | | |
| 3 | TABLE ACCESS BY INDEX ROWID| T1 | 9 | 423 | 6 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | IND_T1_NAME | 9 | | 2 (0)| 00:00:01 |
| 5 | TABLE ACCESS BY INDEX ROWID| T2 | 9 | 423 | 6 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | IND_T2_NAME | 9 | | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("NAME" LIKE 'B%')
filter("NAME" LIKE 'B%')
6 - access("NAME" LIKE 'B%')
filter("NAME" LIKE 'B%')
Note
-----
- dynamic sampling used for this statement