Reputation: 1216
I have this query (in oracle) which takes a very long time (between 15-30secs) (query1):
SELECT numcen
FROM centros
WHERE TO_NUMBER (centros.numcen) = TO_NUMBER (?)
OR TO_NUMBER (centros.numcen) IN (
SELECT TO_NUMBER (dc.centro)
FROM datos_centro dc, centros c
WHERE TO_NUMBER (c.numcen) = TO_NUMBER (dc.centro)
AND TO_NUMBER (dc.centro_superior) = TO_NUMBER (?));
I don't know why, because it's a very simple query. I thought it was because of subquery inside IN
, but if I run such subquery (query2):
SELECT TO_NUMBER (dc.centro)
FROM datos_centro dc, centros c
WHERE TO_NUMBER (c.numcen) = TO_NUMBER (dc.centro)
AND TO_NUMBER (dc.centro_superior) = TO_NUMBER (?)
It only takes 100-200ms.
Even more, if I run query2 and I put its result inside IN
in query1 replacing subquery, result is immediate.
I can't run an Explain Plan because I have no rights.
It's even worse under if I run under mysql (replacing TO_NUMBER
by CAST
). It takes more than 2mins, which is unacceptable.
So, is there a way to improve first query (query1)? Should I split into two? Will it be the same query if I replace OR
by UNION
(which is much faster)?
Any advice will be very welcome. Thanks and sorry for my english.
Upvotes: 0
Views: 376
Reputation: 141
You can do a explain plan on your two queries. explain plan for [ your sql ]; select * from table(dbms_xplan.display);
The optimizer will tell the different between different plans.
Looks to me, the first query will have to use a nested loop and go through each rows in centros and evaluate each record in subquery to filter it out.
The second query will do a hash join between these two tables and do two read then join. This is much less work.
Upvotes: 1
Reputation: 52336
Referencing centros in your subquery is redundant.
try:
SELECT numcen
FROM centros
WHERE TO_NUMBER (centros.numcen) = TO_NUMBER (?)
OR TO_NUMBER (centros.numcen) IN (
SELECT TO_NUMBER (dc.centro)
FROM datos_centro dc
AND TO_NUMBER (dc.centro_superior) = TO_NUMBER (?));
... or ...
SELECT numcen
FROM centros
WHERE TO_NUMBER (centros.numcen) IN (
SELECT TO_NUMBER (?)
FROM dual
UNION ALL
SELECT TO_NUMBER (dc.centro)
FROM datos_centro dc
AND TO_NUMBER (dc.centro_superior) = TO_NUMBER (?));
If you don't need those TO_NUMBER() functions then get rid of them, or add function-based indexes on TO_NUMBER(centros.numcen) and TO_NUMBER (dc.centro_superior).
Upvotes: 0
Reputation: 1145
U just try to use global temp table concept ,insert result set of sub qry in temp table and then use select * from temp table or directly join it with your main qry.
I am sure ,this will improve your performance by manyfold , even i had this issue .
Just give try and let me know if u have any prob.
CREATE GLOBAL TEMPORARY TABLE my_temp_table (
column1 NUMBER) ON COMMIT PRESERVE ROWS;
insert into my_temp_table
SELECT TO_NUMBER (dc.centro)
FROM datos_centro dc, centros c
WHERE TO_NUMBER (c.numcen) = TO_NUMBER (dc.centro)
AND TO_NUMBER (dc.centro_superior) = TO_NUMBER (?)
Upvotes: 0