sure, there are drawbacks.
Now, just to be clear, there are two 'select' constructs you are using here
a) scalar subqueries - a single row, single column query that you use in place of a "column", it looks like a column or function.
b) an inline view - the from (select ... from (select .... ) )
The inline views - great, fine, no problem - we can make them disappear when we optimize.
The scalar subqueries - they should be the exception - not the rule.
You should be JOINING in general. Not using scalar subqueries.
if you have a query
select (select t2.a from t2 where t2.c = t1.c),
col_2,
col_3,
(select t2.b from t2 where t2.c = t1.c),
(select t3.x from t3 where t3.d = t1.d),
from .....
You should just JOIN (outer join if need be) to T2 and T3, it would be:
select t2.a, col_2, col_3, t2.b, t3.x
from ...., T2, T3
where ....
and t2.c(+) = t1.c
and t3.d(+) = t1.d -- outer join IF and ONLY IF necessary
Even if the query was something like:
select (select count(*) from t2 where t2.c = t1.c),
col_2,
col_3,
(select max(b) from t2 where t2.c = t1.c),
(select sum(x) from t3 where t3.d = t1.d),
from .....
you would just
select t2.a, col_2, col_3, t2.b, t3.x
from ...., (select count(*) a, max(b) b, c from t2 group by c) T2,
(select sum(x), d from t3 group by d) T3
where ....
and t2.c(+) = t1.c
and t3.d(+) = t1.d -- outer join IF and ONLY IF necessary
Scalar subqueries can sometimes be useful in "fast return" queries (optimize for initial response time). If you have a "large" query (it would return a TON of data if you fetched the last row) but you get the first 25, then the next 25 and so on (paging through the results for example) - you might use a scalar subquery to get the first 25 rows really fast - and then run the scalar subqueries say 25 times to fill in the blanks.
If you got ALL of the rows this way, it would be very slow, but since you are interested in getting 25 and stopping, getting 25 and stopping - it might be the most efficient way of getting the first 25.
eg:
ops$tkyte%ORA10GR2> /*
ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> drop table t1;
ops$tkyte%ORA10GR2> drop table t2;
ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> create table t1
ops$tkyte%ORA10GR2> as
ops$tkyte%ORA10GR2> select * from all_users;
ops$tkyte%ORA10GR2> alter table t1 add constraint t1_pk primary key(username);
ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> create table t2
ops$tkyte%ORA10GR2> as
ops$tkyte%ORA10GR2> select * from all_objects;
ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> alter table t2 add constraint t2_pk primary key(object_id);
ops$tkyte%ORA10GR2> create index t2_idx on t2(owner);
ops$tkyte%ORA10GR2> */
ops$tkyte%ORA10GR2> @trace
ops$tkyte%ORA10GR2> alter session set events '10046 trace name context forever, level 12';
Session altered.
ops$tkyte%ORA10GR2> declare
2 cursor c1 is select t1.username, count(t2.object_id) cnt
3 from t1, t2
4 where t1.username = t2.owner(+)
5 group by t1.username
6 order by t1.username;
7
8 cursor c2 is select t1.username,
9 (select count(t2.object_id) from t2 where t2.owner = t1.username) cnt
10 from t1
11 order by username;
12
13 type array is table of c1%rowtype index by binary_integer;
14 l_data array;
15
16 begin
17 open c1;
18 fetch c1 bulk collect into l_data limit 10;
19 close c1;
20 open c2;
21 fetch c2 bulk collect into l_data limit 10;
22 close c2;
23 end;
24 /
PL/SQL procedure successfully completed.
Now, you get the same answer, but tkprof shows in this case:
SELECT T1.USERNAME, COUNT(T2.OBJECT_ID) CNT
FROM
T1, T2 WHERE T1.USERNAME = T2.OWNER(+) GROUP BY T1.USERNAME ORDER BY
T1.USERNAME
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 2 0.00 0.00 0 0 0 0
Execute 2 0.00 0.00 0 0 0 0
Fetch 2 0.09 0.09 0 1394 0 20
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 6 0.09 0.09 0 1394 0 20
Misses in library cache during parse: 0
Optimizer mode: ALL_ROWS
Parsing user id: 494 (recursive depth: 1)
Rows Row Source Operation
------- ---------------------------------------------------
10 SORT GROUP BY (cr=697 pr=0 pw=0 time=50132 us)
30112 HASH JOIN OUTER (cr=697 pr=0 pw=0 time=64103 us)
41 INDEX FULL SCAN T1_PK (cr=1 pr=0 pw=0 time=155 us)(object id 171564)
50193 TABLE ACCESS FULL T2 (cr=696 pr=0 pw=0 time=50359 us)
********************************************************************************
SELECT T1.USERNAME, (SELECT COUNT(T2.OBJECT_ID)
FROM
T2 WHERE T2.OWNER = T1.USERNAME) CNT FROM T1 ORDER BY USERNAME
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 2 0.00 0.00 0 0 0 0
Execute 2 0.00 0.00 0 0 0 0
Fetch 2 0.00 0.00 0 28 0 20
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 6 0.00 0.00 0 28 0 20
Misses in library cache during parse: 0
Optimizer mode: ALL_ROWS
Parsing user id: 494 (recursive depth: 1)
Rows Row Source Operation
------- ---------------------------------------------------
10 SORT AGGREGATE (cr=13 pr=0 pw=0 time=379 us)
578 INDEX RANGE SCAN T2_IDX (cr=13 pr=0 pw=0 time=686 us)(object id 171567)
10 INDEX FULL SCAN T1_PK (cr=1 pr=0 pw=0 time=50 us)(object id 171564)