我申请这个blog是为了督促自己,把自己平时的一些想法和思考结果保留下来。 本博客所有内容均为原创,如有转载请注明作者和出处

小议ORDER BY语句中的常数

上一篇 / 下一篇  2007-02-20 00:00:00 / 个人分类:ORACLE

前两天在论坛看到一个问题,本来认为是与全文索引的问题有关,后来却发现是和ORDER BY有关:http://www.itpub.net/showthread.php?s=&threadid=724865


*f*{|7@cG]#T7590422

看到完整的SQL语句后,我就怀疑到问题出在ORDER BY语句中,根据语法,是不能对表名、列名等对象名称采用绑定变量的。

不过由于最近过节,实在是比较懒,也一直没有进行测试,直到今天才验证了一下。

SQL> CREATE TABLE T AS SELECT * FROM DBA_USERS;

表已创建。

SQL> SELECT USER_ID, USERNAME FROM T;

USER_ID USERNAMEITPUB个人空间8S j"{c tv
---------- ------------------------------
t2yOv}0q7590422 0 SYS
N7O-Kfc/B AO7590422 5 SYSTEMITPUB个人空间(?eRJ0d[|
19 DBSNMPITPUB个人空间xA Z;ngeE
27 PROXY_REFRESHER
,[@:`(I6N[B7590422 60 SELEITPUB个人空间 t j9UF6~ t$n
29 SCOTTITPUB个人空间8[| Va,@/_aW;e
28 HR1
5m$@Cv1Yg6O7590422 21 WMSYSITPUB个人空间f/o yS"h b
11 OUTLN
R.P:\[U9rKj gH7590422 26 PROXY_MVIEWADMINITPUB个人空间0n(P5h }~(M'o U
46 TSMITH
{-jk u$oJ9}7590422 25 REPADMIN
Y`g4@ B4A;r ?&FL&Y7590422 30 HR
Rc0Yywt4HE7590422 23 YANGTK

已选择14行。

SQL> SELECT USER_ID, USERNAME FROM T ORDER BY USER_ID;

USER_ID USERNAME
3k3m6N5z;S&i"J7590422---------- ------------------------------ITPUB个人空间)A?,z|;^ J!k5t
0 SYS
:dLHSA^ua s9r7590422 5 SYSTEM
Co0{&h&cn'?2d7590422 11 OUTLNITPUB个人空间u.Ck(zG
19 DBSNMPITPUB个人空间"nSu8h!ww:AA
21 WMSYSITPUB个人空间Fv%e&Q(hD6HXa+O
23 YANGTKITPUB个人空间 N&J i H.dIP
25 REPADMIN
o8BJVUd-Q7590422 26 PROXY_MVIEWADMINITPUB个人空间!]S,W-f'dE
27 PROXY_REFRESHERITPUB个人空间}/x6M9e%N7z Ot4Nw
28 HR1
f~%lH;FT7590422 29 SCOTT
"RgNkC7590422 30 HRITPUB个人空间ftw t'K!{:dSl
46 TSMITHITPUB个人空间O,c{|3?T
60 SELE

已选择14行。

SQL> SELECT USER_ID, USERNAME FROM T ORDER BY 1;

USER_ID USERNAME
ju5^y/ekv7590422---------- ------------------------------ITPUB个人空间HQ8x&{xkNQ
0 SYSITPUB个人空间:Ja n0Id z3t/zA1p
5 SYSTEM
)u.v.V xS#Aa/x7590422 11 OUTLN
.c W(M1|n R8a X7590422 19 DBSNMP
3s;[ _s#T%qr0h[7590422 21 WMSYS
-Ir,r Od7590422 23 YANGTKITPUB个人空间$?liNb*C
25 REPADMINITPUB个人空间g$K4^ ys&|YB
26 PROXY_MVIEWADMIN
@7A$}Y1? ^M7590422 27 PROXY_REFRESHERITPUB个人空间,O"u!x9]W"GU
28 HR1
k c ^1p{A{ {d(y7590422 29 SCOTTITPUB个人空间&^!O0Ct0B
30 HRITPUB个人空间 g4Er7k/wJB"L
46 TSMITHITPUB个人空间]!zk p-L2V
60 SELE

已选择14行。

上面是ORDER BY的两种基本用法,一种是指定SELECT语句列表中的列表或别名,另一种是列的位置。

如果这里采用帮定变量,那么结果是什么呢?

SQL> SELECT USER_ID, USERNAME FROM T ORDER BY :NAME;

USER_ID USERNAMEITPUB个人空间?ZOX/|V%B K
---------- ------------------------------
e7p)O\8})N4q1](Q7590422 0 SYS
B/E!^|[Ef7590422 5 SYSTEMITPUB个人空间|WxEc2xc [
19 DBSNMP
l/fu4z/C0U Rl` K@7590422 27 PROXY_REFRESHERITPUB个人空间]t1t$\!}H/K+d6r
60 SELEITPUB个人空间D XX` b$v
29 SCOTT
S H*@ mn e#ySZ7590422 28 HR1ITPUB个人空间7Ej7Z)Z h
21 WMSYS
RfAv$`a7590422 11 OUTLN
`Pv~uJ O#P9V8z8v7590422 26 PROXY_MVIEWADMINITPUB个人空间'`HyO&A?-l!M
46 TSMITH
}B'c.bg9R^o+mJE7590422 25 REPADMIN
;qM ID,{i0O7590422 30 HR
$gtZ`U#sfN8p7590422 23 YANGTK

已选择14行。

通过上面的结果可以看到,Oracle虽然没有报错,可以正常执行,但是并没有根据USERNAME列进行排序。

实际上,根据绑定变量的特点,这里输入的USERNAME并不是列名,而是一个字符串常量,因此上面的SQL等价于:

SQL> SELECT USER_ID, USERNAME FROM T ORDER BY 'USERNAME';

USER_ID USERNAMEITPUB个人空间*u7K!v1rF
---------- ------------------------------ITPUB个人空间/U V;^2Hlp J~v
0 SYS
6jvEs C YO(U7590422 5 SYSTEM
~5|a;y];_ Hd7590422 19 DBSNMP
"x"Kb6{o}Wg\Eg7590422 27 PROXY_REFRESHERITPUB个人空间 i q0sj\%`4y
60 SELE
&y4K+RV u3w)T$O3{7590422 29 SCOTTITPUB个人空间3JvNhy
28 HR1ITPUB个人空间5R9I&c.m4X9Z
21 WMSYS
NgY#o6k K H4?U\2x7590422 11 OUTLN
2b3{G [H l7590422 26 PROXY_MVIEWADMINITPUB个人空间2SHl0I/vK"WUv
46 TSMITH
yf*[MD:ki7590422 25 REPADMINITPUB个人空间&f?o `-V8bO
30 HRITPUB个人空间-?(V`,NYP|
23 YANGTK

已选择14行。

而且通过测试发现,查询结果与ORDER BY中的字符串常量的内容没有关系,与ASC和DESC关键字也没有任何关系:

SQL> SELECT USER_ID, USERNAME FROM T ORDER BY 'ABC';

USER_ID USERNAMEITPUB个人空间1a+?([0}9W8T4I
---------- ------------------------------
:J3o%F4e-sK ?3e f%D'E7590422 0 SYS
x O{h n zO7590422 5 SYSTEM
4Fm9UW5K#s-y7590422 19 DBSNMPITPUB个人空间F YH5?o
27 PROXY_REFRESHER
xo_*__{E7590422 60 SELE
|G&p+jdr7590422 29 SCOTTITPUB个人空间 Ld0w'o%F R
28 HR1ITPUB个人空间nFGJ5K4L i2N
21 WMSYS
(ou3g:P&N7p)co[`7590422 11 OUTLNITPUB个人空间,W jp*l"iWig3d
26 PROXY_MVIEWADMIN
3C*~ }6W xP7590422 46 TSMITHITPUB个人空间Pm:s`#MTVJt
25 REPADMIN
"S*M,|0A9S7590422 30 HR
\v7[K[w!uv1i'}7590422 23 YANGTK

已选择14行。

SQL> SELECT USER_ID, USERNAME FROM T ORDER BY '2';

USER_ID USERNAMEITPUB个人空间luA2e k:W X0YM2x4?
---------- ------------------------------ITPUB个人空间^6JL$j WX f
0 SYSITPUB个人空间B1EYe d5C/\_u*}:DL2t
5 SYSTEMITPUB个人空间*q ~(ijU F_ v&i(suu$T
19 DBSNMPITPUB个人空间1w;de6oW'x mu
27 PROXY_REFRESHER
&n#U-uLjB7590422 60 SELEITPUB个人空间,{PF)_P
29 SCOTT
:U#U4V-Bv%Pu7590422 28 HR1ITPUB个人空间 bVs XtK*wNKs
21 WMSYSITPUB个人空间L { a GC1X
11 OUTLNITPUB个人空间 s]+V3h(ba9l
26 PROXY_MVIEWADMINITPUB个人空间wNx,x wtY#c
46 TSMITH
F*\W%sU[7590422 25 REPADMIN
yk)M$vV2Na7590422 30 HRITPUB个人空间[8kIhQ-a
23 YANGTK

已选择14行。

SQL> SELECT USER_ID, USERNAME FROM T ORDER BY SYSDATE DESC;

USER_ID USERNAME
/n;e2q:N,Z#s7590422---------- ------------------------------
Yue;[4rJ7590422 0 SYSITPUB个人空间+o"I\3{!hnt^5lj"O.Z
5 SYSTEMITPUB个人空间.I!\o f3`;I r
19 DBSNMPITPUB个人空间qS5Tbf,u"r(]{A
27 PROXY_REFRESHER
;`'v#P4zs \-`'B7590422 60 SELE
;ravz;E Yg-{T7590422 29 SCOTTITPUB个人空间a` KRz8C
28 HR1ITPUB个人空间 P0Dp*G%G^
21 WMSYS
S&E9Q0J%t7590422 11 OUTLNITPUB个人空间;cE'U,K7g*Rq
26 PROXY_MVIEWADMINITPUB个人空间vPFWK
46 TSMITHITPUB个人空间v2I YO8pGzE
25 REPADMINITPUB个人空间;y2SP+e.WtyChB
30 HRITPUB个人空间RLZe)gV
23 YANGTK

已选择14行。

那么Oracle在这种情况下到底是根据什么进行的排序呢?

SQL> SET AUTOT ONITPUB个人空间H$Z7@X$b.A^8^.b
SQL> SELECT USER_ID, USERNAME FROM T ORDER BY 'USERNAME';

USER_ID USERNAME
;m,?M \2y z7590422---------- ------------------------------
7K`9G:r0{IL(t"@7590422 0 SYSITPUB个人空间$ieS$GE/E
5 SYSTEM
#nZ8K CN-|(bv7b\7590422 19 DBSNMPITPUB个人空间'f!e/zg0k"ky$oD,|
27 PROXY_REFRESHERITPUB个人空间qK {cq.~%VF%n`
60 SELE
*['iDDV5a`oN K7590422 29 SCOTTITPUB个人空间UV Q8{5dZ}y/G
28 HR1ITPUB个人空间IG z;?&E;Q
21 WMSYS
1N/q-Jk^#ss1XW1f7590422 11 OUTLN
9`4nZ mfp7590422 26 PROXY_MVIEWADMIN
4aA}/gA:z7590422 46 TSMITH
/Zg9T'nw7590422 25 REPADMINITPUB个人空间'woC'q)t
30 HRITPUB个人空间F Zd? S b
23 YANGTK

已选择14行。

ITPUB个人空间R-h| QD(zON \+iW
Execution Plan
"q7ob4rM7590422----------------------------------------------------------ITPUB个人空间9Rk:^S8VO
0 SELECT STATEMENT Optimizer=CHOOSEITPUB个人空间`4ll0J sF
1 0 TABLE ACCESS (FULL) OF 'T'

ITPUB个人空间2R#s+O Q;O0}d
Statistics
Zt~+x Ihc7590422----------------------------------------------------------ITPUB个人空间B4ufM2_ TykNz
0 recursive callsITPUB个人空间@$iT X e1{)TAH
0 db block getsITPUB个人空间1R E6J3d@
4 consistent gets
~!@2gCR^2]}7590422 0 physical readsITPUB个人空间*g3}jG2PD
0 redo size
/}U9|(S5A(D%j"n7590422 665 bytes sent via SQL*Net to clientITPUB个人空间MpK0\1A5HFmR
503 bytes received via SQL*Net from client
7fg3u/F/l/J7590422 2 SQL*Net roundtrips to/from clientITPUB个人空间*B&w-k$GC6zo%`
0 sorts (memory)
"Kg SF:RR9D:R*o7590422 0 sorts (disk)
'Nz\%q!C {:z7590422 14 rows processed

从执行计划和统计信息都可以看到,Oracle实际上并没有进行排序。这其实就是问题的原因。当ORDER BY语句中的常量不是SELECT列表的位置时,Oracle实际上没有执行任何地排序。

最后描述一下ORDER BY语句使用列的位置的情况:

SQL> SELECT USER_ID, USERNAME FROM T ORDER BY 5;ITPUB个人空间~0Tw N#U.@ \
SELECT USER_ID, USERNAME FROM T ORDER BY 5
D eR.i-B5X'w7590422 *ITPUB个人空间^"U#li2yyv\
ERROR 位于第 1 行:ITPUB个人空间,RR PyQ
ORA-01785: ORDER BY 项必须是 SELECT-list 表达式的数目


DF0J!K-ts7590422SQL> VAR POSITION NUMBER
`MV%Kk7PHm7590422SQL> EXEC :POSITION := 2

PL/SQL 过程已成功完成。

SQL> SELECT USER_ID, USERNAME FROM T ORDER BY :POSITION;

USER_ID USERNAME
:I+G+hd4GOOs0c"|$}7590422---------- ------------------------------ITPUB个人空间 O6c/z8dH5R;S
0 SYSITPUB个人空间BF6z;P+v0S@+P{ B
5 SYSTEM
~qeHw/_7590422 19 DBSNMPITPUB个人空间 Vexn0i3u,QYxMw:K
27 PROXY_REFRESHER
7v ^.W.J5{?7590422 60 SELEITPUB个人空间GTQ(G.Kl
29 SCOTT
ap\ E waV'LM\7590422 28 HR1ITPUB个人空间D w/Rn x @
21 WMSYSITPUB个人空间?+Y_t2gw,N
11 OUTLN
I6eAb5_ SO7P:`7590422 26 PROXY_MVIEWADMIN
$qg6\^eve)ZO7590422 46 TSMITHITPUB个人空间6tZfcn8tex im h4B0IV
25 REPADMIN
m8i!rHW|7590422 30 HRITPUB个人空间 x&S`O? ak
23 YANGTK

已选择14行。


4_s}o~y:vO1Kf~7590422Execution PlanITPUB个人空间!UY oPB*L*[r
----------------------------------------------------------
ravhg7590422 0 SELECT STATEMENT Optimizer=CHOOSEITPUB个人空间O?4Kqs
1 0 TABLE ACCESS (FULL) OF 'T'

ITPUB个人空间uH+D)L9^V-Sz o
Statistics
d pLc4b9P~ p_7590422----------------------------------------------------------ITPUB个人空间 q}C8A kiUn};_
0 recursive callsITPUB个人空间gZE*g7F
0 db block getsITPUB个人空间 E$t4T y5|
4 consistent getsITPUB个人空间 v [2M&TEzC+xI"V
0 physical readsITPUB个人空间[+|P(vO~;O.vk b'R
0 redo size
G3A0C"f%Z0P+L:tE7590422 665 bytes sent via SQL*Net to clientITPUB个人空间;yTP6Q!s[h+vW0T]
503 bytes received via SQL*Net from client
fqHHK"?7590422 2 SQL*Net roundtrips to/from client
Nu A|W&S\&^ Q7}*]7590422 0 sorts (memory)
L PnzN)c:XB7590422 0 sorts (disk)ITPUB个人空间4@o+~(s%G'^ F
14 rows processed

从上面两个查询其实以及不难推断出,ORDER BY语句中的列的位置,实际上是替换为列的名字或别名,而且这个操作是在语句分析时就完成的,也就是说在绑定变量输入值之前就完成了,这就是为什么ORDER BY中即使绑定一个NUMBER型变量,并输入一个存在的列的位置,而Oracle却并没有进行排序。

简单总结一下,ORDER BY中可以包含常量,但是除了NUMBER类型的表示列的位置的情况外,输入其他的常量,都会导致Oracle直接忽略排序操作。也就是说,ORDER BY后面也不应该使用绑定变量,如果ORDER BY的列是会发生变化或无法在编译时确定的,应该使用动态SQL语句,而不是绑定变量。


TAG:

 

评分:0

我来说两句

显示全部

:loveliness: :handshake :victory: :funk: :time: :kiss: :call: :hug: :lol :'( :Q :L ;P :$ :P :o :@ :D :( :)

Open Toolbar