a我考网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 203|回复: 1

[其他] Oracle认证:增加Distinct提高查询效率

[复制链接]
发表于 2012-8-4 13:41:06 | 显示全部楼层 |阅读模式
只有增添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
  ----------------------------------------------------------
回复

使用道具 举报

 楼主| 发表于 2012-8-4 13:41:07 | 显示全部楼层

Oracle认证:增加Distinct提高查询效率

</p>  0 recursive calls
5 j7 v' j. v8 \0 D' X) r2 E  0 db block gets
+ y. {+ F' R4 v: f' b" \  93 consistent gets
9 {4 P; c' ]5 ^  L7 M1 Y2 V, ?  0 physical reads8 S- K9 t- _5 o; X& Q& p
  0 redo size
2 H- d+ y" s0 \  8843 bytes sent via SQL*Net to client
# D2 q/ l) D8 g1 b8 h  h  X! @+ M  723 bytes received via SQL*Net from client
* _! C2 P3 F1 `0 j) B/ W  22 SQL*Net roundtrips to/from client& [- z: }. i* k) o2 p% _
  0 sorts (memory)  S. H: C3 U% n" o1 q4 @+ o
  0 sorts (disk)# L, x1 b, G+ T$ Y/ ], v' I
  311 rows processed1 ^$ p" K: X3 M$ ^$ [
  SQL> SELECT DISTINCT T1.OBJECT_NAME, T1.OBJECT_TYPE, T2.TABLESPACE_NAME# ?0 ^. z% m+ R5 G2 K
  2 FROM T1, T2
2 B( V. P, l0 f7 \( e/ z  3 WHERE T1.OBJECT_NAME = T2.SEGMENT_NAME
2 ?% X# w$ _2 ^& q) l  4 AND T1.OBJECT_NAME IN
: B4 e* D) E* L: @' f- c( I. |  5 (
7 y' E: J' v  z7 m0 S  6 SELECT INDEX_NAME FROM T3" D% b7 r( M5 R" g5 G4 ?
  7 WHERE T3.TABLESPACE_NAME = T2.TABLESPACE_NAME
$ W/ W( A+ t7 o% ?  8 );; M9 p9 {. e: [% d/ g
  311 rows selected.9 s; B: x; r. P( n( h
  Execution Plan, q& H- K+ _8 c9 q9 C
  ----------------------------------------------------------. M- l6 I+ Z- [: O+ R6 Y) T
  0 SELECT STATEMENT Optimizer=CHOOSE (Cost=16 Card=1 Bytes=93)
2 {; }. @; E" I  1 0 SORT (UNIQUE) (Cost=16 Card=1 Bytes=93)8 [' n! O; t& u7 H, c3 X2 i; x! J
  2 1 HASH JOIN (Cost=12 Card=1 Bytes=93)* }! |# n; E3 v3 O  Q
  3 2 HASH JOIN (Cost=5 Card=668 Bytes=44088)2 K& Y, U4 d4 ?' _# t' ^  n3 P. M( d  @
  4 3 TABLE ACCESS (FULL) OF 'T3' (Cost=2 Card=340 Bytes=11560)
2 b3 r: b" Q8 Y& k  5 3 TABLE ACCESS (FULL) OF 'T2' (Cost=2 Card=668 Bytes=21376)  i9 i: w; y! T% q# l8 x  f; }& ^
  6 2 TABLE ACCESS (FULL) OF 'T1' (Cost=6 Card=3806 Bytes=102762)
* c: U  I3 Y/ o# Z, Y- j  Statistics
$ G7 w  y3 K" @; H: H  E  ----------------------------------------------------------* d" M$ O8 H! Y7 x4 x# _
  0 recursive calls" {6 S5 M; i1 ]7 k% e
  0 db block gets
! o. d6 ]  J9 L) k6 G8 b  72 consistent gets$ J/ v% H) E4 `8 c) @9 ~8 G
  0 physical reads8 ^* ^# b  _- [/ \# q
  0 redo size. K7 a5 Y$ I. J
  8843 bytes sent via SQL*Net to client
" N( Z) y$ A( |# [* I  723 bytes received via SQL*Net from client
8 S) M  s1 c( i3 F8 ?& |9 G  22 SQL*Net roundtrips to/from client9 I0 H$ ?3 A! K% ]8 m
  1 sorts (memory)8 g8 W6 I# Q1 o5 Q
  0 sorts (disk)
0 C5 V" L3 K9 V0 f0 K% V  311 rows processed 8 e( X: ^! G+ G: ~
( G1 B. d9 |" P! R! P
        年夜统计信息可以看出,添加了DISTINCT后,语句的逻辑读反而比不加DISTINCT要高。为什么会发生这种情形,还要年夜执行打算说起。& }2 L: @" b8 c1 V0 J$ ~, O" {
  不加DISTINCT的情形,因为使用IN子发芽的发芽,Oracle对第二个毗连采用了HASH JOIN SEMI,这种HASH JOIN SEMI相对于通俗的HASH JOIN,价钱要年夜一些。+ `3 Z5 q& P; v* {( P
  而添加了DISTINCT之后,Oracle知道最终必定要进行排序去重的操作,是以在毗连的时辰就选择了HASH JOIN作为了毗连体例。这就是为什么加上了DISTINCT之后,逻辑读反而削减了。可是同时,加上了DISTINCT之后,语句增添了一个排序操作,而在不加DISTINCT的时辰,是没有这个操作的。
4 }  X% |, X# U3 ~* T; z  e  当毗连的表数据量很年夜,可是SELECT的最终结不美观不是良多,且SELECT列的个数不是良多的时辰,加上DISTINCT之后,这个排序的价钱要小于SEMI JOIN毗连的价钱。这就是增添一个DISTINCT操作发芽效率反而提高,这个似乎不成能发生的情形的真正原因。" k7 Q4 B, t4 G) `8 N; q" y3 S
  最后需要声名一下,这篇文丈廒声名,优化的时辰没有什么工具是一成不变的,几乎任何工作都有可能发生,不要被一些所谓死轨则限制住。年夜白了这一点就可以了。这篇文章并不是筹算供给一种优化SQL的体例,严酷意义年夜将,加上DISTINCT和不加DISTINCT是两个完全分歧的SQL语句。虽然在这个例子中,二者是等价的,可是这是表结构、约束前提和数据自己配合限制的结不美观。换了另一个情形,这两个SQL获得的结不美观可能会相去甚远,所以,不要试图将本文的例子作为优化时的一种体例。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Woexam.Com ( 湘ICP备18023104号 )

GMT+8, 2024-5-16 03:59 , Processed in 0.186215 second(s), 23 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表