現象
環境:oracle 11.2.0.4
今天客戶說,一個檢視查詢很慢,讓幫忙分析。
分析後,發現是rownum導致的檢視不能走索引。
模擬
對原查詢進行簡化模擬:
這裏modify_time列為varchar2型別,但是因為某些原因,web套用查詢該欄位必須使用date型別,所以我在該列上建立了函式索引:
1DROPTABLE TB;
2CREATETABLE TB(IDINT, modify_time varchar2(14));
3
4INSERTINTO TB (id,modify_time)
5SELECTrownum, to_char(sysdate + rownum,'YYYYMMDDHH24MISS')
6from dual
7CONNECTBYLEVEL <= 20000;
8
9createindex idx_1 on tb(to_date(modify_time,'YYYYMMDDHH24MISS'));
10createindex idx_2 on tb(modify_time);
11
12begin DBMS_STATS.gather_table_stats('lhr', 'tb',cascade => TRUE, DEGREE=>16,no_invalidate => false); end;
13
14
15
16createorreplaceview vw1
17as
18selectid,modify_time,to_date(modify_time,'YYYYMMDDHH24MISS') modify_at,to_date(modify_time,'YYYYMMDDHH24miss') modify_at1
19from tb
20;
21
22createorreplaceview vw2
23as
24selectid,modify_time,to_date(modify_time,'YYYYMMDDHH24MISS') modify_at,rownum rn
25from tb
26;
27
28-- 走索引
29
30select * from vw1 where modify_time= '2024-03-01';
31select * from vw1 where modify_at= to_date('2024-03-01','yyyy-mm-dd');
32select * from vw1 where modify_at= to_date('20240301000000','syyyy-mm-dd hh24:mi:ss');
33
34-- 不走索引(to_date函式大小寫問題)
35select * from vw1 where modify_at1= to_date('2024-03-01','yyyy-mm-dd');
36
37-- 不走索引(rownum問題)
38select * from vw2 where modify_at= to_date('2024-03-01','yyyy-mm-dd');
39select * from vw2 where modify_time= '2024-03-01';
執行計劃:
1SYS@LHR11G> conn lhr/lhr
2Connected.
3LHR@LHR11G> set autot on
4LHR@LHR11G> select * from vw1 where modify_at= to_date('2024-03-01','yyyy-mm-dd');
5
6no rows selected
7
8
9Execution Plan
10----------------------------------------------------------
11Plan hash value: 4159717772
12
13-------------------------------------------------------------------------------------
14| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
15-------------------------------------------------------------------------------------
16| 0 | SELECTSTATEMENT | | 1 | 31 | 1 (0)| 00:00:01 |
17| 1 | TABLEACCESSBYINDEXROWID| TB | 1 | 31 | 1 (0)| 00:00:01 |
18|* 2 | INDEXRANGESCAN | IDX_1 | 1 | | 1 (0)| 00:00:01 |
19-------------------------------------------------------------------------------------
20
21Predicate Information (identifiedby operation id):
22---------------------------------------------------
23
242 - access(TO_DATE("MODIFY_TIME",'YYYYMMDDHH24MISS')=TO_DATE(' 2024-03-01
25 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
26
27Note
28-----
29 - dynamic sampling used for this statement (level=2)
30
31
32Statistics
33----------------------------------------------------------
3421recursive calls
350 db block gets
36150consistent gets
371physicalreads
380redosize
39473bytes sent via SQL*Net toclient
40512bytes received via SQL*Net fromclient
411SQL*Net roundtrips to/fromclient
420 sorts (memory)
430 sorts (disk)
440rows processed
45
46LHR@LHR11G> select * from vw1 where modify_at= to_date('20240301000000','syyyy-mm-dd hh24:mi:ss');
47
48no rows selected
49
50
51Execution Plan
52----------------------------------------------------------
53Plan hash value: 4159717772
54
55-------------------------------------------------------------------------------------
56| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
57-------------------------------------------------------------------------------------
58| 0 | SELECTSTATEMENT | | 1 | 31 | 1 (0)| 00:00:01 |
59| 1 | TABLEACCESSBYINDEXROWID| TB | 1 | 31 | 1 (0)| 00:00:01 |
60|* 2 | INDEXRANGESCAN | IDX_1 | 1 | | 1 (0)| 00:00:01 |
61-------------------------------------------------------------------------------------
62
63Predicate Information (identifiedby operation id):
64---------------------------------------------------
65
662 - access(TO_DATE("MODIFY_TIME",'YYYYMMDDHH24MISS')=TO_DATE('202403010000
67 00','syyyy-mm-dd hh24:mi:ss'))
68
69Note
70-----
71 - dynamic sampling used for this statement (level=2)
72
73
74Statistics
75----------------------------------------------------------
7621recursive calls
770 db block gets
78150consistent gets
790physicalreads
800redosize
81473bytes sent via SQL*Net toclient
82512bytes received via SQL*Net fromclient
831SQL*Net roundtrips to/fromclient
840 sorts (memory)
850 sorts (disk)
860rows processed
87
88LHR@LHR11G> select * from vw1 where modify_at1= to_date('2024-03-01','yyyy-mm-dd');
89
90no rows selected
91
92
93Execution Plan
94----------------------------------------------------------
95Plan hash value: 2878482057
96
97--------------------------------------------------------------------------
98| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
99--------------------------------------------------------------------------
100| 0 | SELECTSTATEMENT | | 1 | 31 | 22 (0)| 00:00:01 |
101|* 1 | TABLEACCESSFULL| TB | 1 | 31 | 22 (0)| 00:00:01 |
102--------------------------------------------------------------------------
103
104Predicate Information (identifiedby operation id):
105---------------------------------------------------
106
1071 - filter(TO_DATE("MODIFY_TIME",'YYYYMMDDHH24miss')=TO_DATE('
108 2024-03-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
109
110Note
111-----
112 - dynamic sampling used for this statement (level=2)
113
114
115Statistics
116----------------------------------------------------------
1170recursive calls
1180 db block gets
11976consistent gets
1200physicalreads
1210redosize
122473bytes sent via SQL*Net toclient
123512bytes received via SQL*Net fromclient
1241SQL*Net roundtrips to/fromclient
1250 sorts (memory)
1260 sorts (disk)
1270rows processed
128
129LHR@LHR11G> select * from vw2 where modify_at= to_date('2024-03-01','yyyy-mm-dd');
130
131no rows selected
132
133
134Execution Plan
135----------------------------------------------------------
136Plan hash value: 1470101981
137
138----------------------------------------------------------------------------
139| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
140----------------------------------------------------------------------------
141| 0 | SELECTSTATEMENT | | 19745 | 674K| 22 (0)| 00:00:01 |
142|* 1 | VIEW | VW2 | 19745 | 674K| 22 (0)| 00:00:01 |
143| 2 | COUNT | | | | | |
144| 3 | TABLEACCESSFULL| TB | 19745 | 424K| 22 (0)| 00:00:01 |
145----------------------------------------------------------------------------
146
147Predicate Information (identifiedby operation id):
148---------------------------------------------------
149
1501 - filter("MODIFY_AT"=TO_DATE(' 2024-03-01 00:00:00', 'syyyy-mm-dd
151 hh24:mi:ss'))
152
153Note
154-----
155 - dynamic sampling used for this statement (level=2)
156
157
158Statistics
159----------------------------------------------------------
16021recursive calls
1610 db block gets
162216consistent gets
1630physicalreads
1640redosize
165465bytes sent via SQL*Net toclient
166512bytes received via SQL*Net fromclient
1671SQL*Net roundtrips to/fromclient
1680 sorts (memory)
1690 sorts (disk)
1700rows processed
171
172LHR@LHR11G> select * from vw1 where modify_time= '2024-03-01';
173
174no rows selected
175
176
177Execution Plan
178----------------------------------------------------------
179Plan hash value: 956939525
180
181-------------------------------------------------------------------------------------
182| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
183-------------------------------------------------------------------------------------
184| 0 | SELECTSTATEMENT | | 1 | 31 | 1 (0)| 00:00:01 |
185| 1 | TABLEACCESSBYINDEXROWID| TB | 1 | 31 | 1 (0)| 00:00:01 |
186|* 2 | INDEXRANGESCAN | IDX_2 | 1 | | 1 (0)| 00:00:01 |
187-------------------------------------------------------------------------------------
188
189Predicate Information (identifiedby operation id):
190---------------------------------------------------
191
1922 - access("MODIFY_TIME"='2024-03-01')
193
194Note
195-----
196 - dynamic sampling used for this statement (level=2)
197
198
199Statistics
200----------------------------------------------------------
20137recursive calls
2020 db block gets
20381consistent gets
2040physicalreads
2050redosize
206546bytes sent via SQL*Net toclient
207512bytes received via SQL*Net fromclient
2081SQL*Net roundtrips to/fromclient
2090 sorts (memory)
2100 sorts (disk)
2110rows processed
212
213LHR@LHR11G> select * from vw2 where modify_time= '2024-03-01';
214
215no rows selected
216
217
218Execution Plan
219----------------------------------------------------------
220Plan hash value: 1470101981
221
222----------------------------------------------------------------------------
223| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
224----------------------------------------------------------------------------
225| 0 | SELECTSTATEMENT | | 19745 | 848K| 22 (0)| 00:00:01 |
226|* 1 | VIEW | VW2 | 19745 | 848K| 22 (0)| 00:00:01 |
227| 2 | COUNT | | | | | |
228| 3 | TABLEACCESSFULL| TB | 19745 | 597K| 22 (0)| 00:00:01 |
229----------------------------------------------------------------------------
230
231Predicate Information (identifiedby operation id):
232---------------------------------------------------
233
2341 - filter("MODIFY_TIME"='2024-03-01')
235
236Note
237-----
238 - dynamic sampling used for this statement (level=2)
239
240
241Statistics
242----------------------------------------------------------
24321recursive calls
2440 db block gets
245218consistent gets
2460physicalreads
2470redosize
248538bytes sent via SQL*Net toclient
249512bytes received via SQL*Net fromclient
2501SQL*Net roundtrips to/fromclient
2510 sorts (memory)
2520 sorts (disk)
2530rows processed
254
255LHR@LHR11G>
透過10053事件,發現SQL語句最終被修改成:
1-- 原SQL
2select * from vw2 where modify_time= '2024-03-01';
3
4-- 內部執行
5SELECT"VW2"."ID""ID","VW2"."MODIFY_TIME""MODIFY_TIME","VW2"."MODIFY_AT""MODIFY_AT","VW2"."RN""RN"FROM (SELECT"TB"."ID""ID","TB"."MODIFY_TIME""MODIFY_TIME",TO_DATE("TB"."MODIFY_TIME",'YYYYMMDDHH24MISS') "MODIFY_AT",ROWNUM"RN"FROM LHR."TB""TB") "VW2"WHERE"VW2"."MODIFY_TIME"='2024-03-01'
總結
1、to_date函式索引的大小寫要和使用時的大小寫和格式一致,否則也會不走索引
2、若檢視中含有rownum偽列,則不會走索引
3、其它情況導致的不能走索引(索引失效)情況請參考:https://www.xmmup.com/oracleweihezaichaxunzhongsuoyinweibeishiyong-wendang-id-1549181-1.html
參考
https://asktom.oracle.com/ords/f?p=100:11:0::::P11_QUESTION_ID:32812348052
https://blog.csdn.net/sharqueen_wu/article/details/42105477
https://blog.csdn.net/bisal/article/details/9713621