只有增添DISTINCT关头字,Oracle必然需要对后面的所有字段进行排序。以前也经常发现因为开发人员对SQL不是很理解,在SELECT列表的20多个字段前面添加了DISTINCT,造成发芽根基上不成能执行完成,甚至发生ORA-7445错误。所以一向向开发人员强调DISTINCT给机能带来的影响。 没想到开发人员在测试一条年夜的SQL的时辰,告诉我如不美观加上了DISTINCT,则发芽概略需要4分钟摆布可以执行完,如不美观不加DISTINCT,则发芽执行了10多分钟,仍然得不到结不美观。6 c; m) N; s+ h6 H: I# g
首先想到的是可能DISTINCT是在子发芽中,因为加上了DISTINCT,将第一步结不美观集缩小了,导致发芽机能提高,结不美观一看SQL,发现DISTINCT居然是在发芽的最外层。
/ g" K+ v* b( D 因为原始SQL太长,而且牵扯的表太多,很难说清嚣张,这里模拟了一个例子,这个例子因为数据量和SQL的复杂水平限制,无法看出二者执行时刻上的较着分歧。这老迈两种情形的逻辑读对比来声名问题。
) ^4 [# D* `& ^% _ 首先成立模拟情形: % M* u* v5 }. n
SQL> CREATE TABLE T1 AS SELECT * FROM DBA_OBJECTS
2 @: Y' S1 E' N# Q 2 WHERE OWNER = 'SYS'. s9 U8 C. o: ^, c0 @+ m
3 AND OBJECT_TYPE NOT LIKE '%BODY'
: s2 N( q, w+ f3 n/ K 4 AND OBJECT_TYPE NOT LIKE 'JAVA%';0 O. C6 H+ P4 O
Table created.
' O9 N T$ Y) t* N- y. J& V SQL> CREATE TABLE T2 AS SELECT * FROM DBA_SEGMENTS WHERE OWNER = 'SYS';
# U( ?+ N! t' G7 Z, h( U1 r Table created.
; W1 @0 E3 V. {# h0 G* y SQL> CREATE TABLE T3 AS SELECT * FROM DBA_INDEXES WHERE OWNER = 'SYS';" G4 c' I$ z) n" H8 b. b! ]- L
Table created.% c3 o% O& F) ? F- p. Z2 N7 Z
SQL> ALTER TABLE T1 ADD CONSTRAINT PK_T1 PRIMARY KEY (OBJECT_NAME);7 P6 Z* h0 {% ]
Table altered. y0 l; A7 l5 {/ z1 |
SQL> CREATE INDEX IND_T2_SEGNAME ON T2(SEGMENT_NAME);
, T% g4 i9 W7 X# K1 T5 S+ ~ Index created.
& G3 y" _' s: Z" _: {; u8 L3 |% O SQL> CREATE INDEX IND_T3_TABNAME ON T3(TABLE_NAME);
. N$ E8 X* r8 V/ h' v Index created.
% [) i9 @- A3 [$ Q1 J' `5 P) p x9 ^# u; l SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS(USER, 'T1', METHOD_OPT => 'FOR ALL INDEXED COLUMNS SIZE 100', CASCADE => TRUE)1 I0 K0 f( `2 L. X* l2 O
PL/SQL procedure successfully completed.
9 o) m+ ?! d( O SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS(USER, 'T2', METHOD_OPT => 'FOR ALL INDEXED COLUMNS SIZE 100', CASCADE => TRUE)- f- [0 K- d9 ?8 n. H
PL/SQL procedure successfully completed.5 k$ R; ]4 M; A0 K9 m, X
SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS(USER, 'T3', METHOD_OPT => 'FOR ALL INDEXED COLUMNS SIZE 100', CASCADE => TRUE)7 @9 N) A7 O5 L
PL/SQL procedure successfully completed. # f! O# t* `2 n- ~0 r
仍然沿用膳缦沔例子中的结构,看看原始SQL和增添DISTINCT后的分歧:4 f! B5 s G' E& j/ d' A
2 l! Z9 F9 [ gSQL> SET AUTOT TRACE
* g+ N2 D' c3 ^( Q" x3 J2 {- J8 t: V SQL> SELECT T1.OBJECT_NAME, T1.OBJECT_TYPE, T2.TABLESPACE_NAME
0 y( j5 }( ]% a4 r7 w; U) ~; [% F 2 FROM T1, T2
' R" n! ^- F" g x3 b0 R 3 WHERE T1.OBJECT_NAME = T2.SEGMENT_NAME
, Z! l/ `1 O" B6 M6 j 4 AND T1.OBJECT_NAME IN$ F/ h, `, R7 R! a, G
5 (
1 _+ [8 I( q7 A5 b/ t+ T. c 6 SELECT INDEX_NAME FROM T3
2 t% k6 j" V; v }$ M 7 WHERE T3.TABLESPACE_NAME = T2.TABLESPACE_NAME
3 o3 n1 r/ K! n, V( z: M- L 8 );3 C; |' @# ^ f
311 rows selected.
* c* V- [# E+ v Execution Plan
. _2 u( Z: O+ n6 M ----------------------------------------------------------
* p! s% u; P+ ~8 G$ e1 w) j 0 SELECT STATEMENT Optimizer=CHOOSE (Cost=12 Card=668 Bytes=62124). Q( W5 \9 Z" F) ]
1 0 HASH JOIN (SEMI) (Cost=12 Card=668 Bytes=62124)
% M! f( Y; K$ z- X+ n4 K 2 1 HASH JOIN (Cost=9 Card=668 Bytes=39412)- W# e8 a3 R2 ?8 Y$ x) b1 e
3 2 TABLE ACCESS (FULL) OF 'T2' (Cost=2 Card=668 Bytes=21376)
( N F& w+ p% g 4 2 TABLE ACCESS (FULL) OF 'T1' (Cost=6 Card=3806 Bytes=102762)# \" D9 z" P2 s6 B6 Q
5 1 TABLE ACCESS (FULL) OF 'T3' (Cost=2 Card=340 Bytes=11560). x- V, g u5 B3 `5 E9 j3 Z
Statistics1 C7 i) V2 |) Z4 k' _# r% `: L
---------------------------------------------------------- |