简体   繁体   中英

How to fix my query so the filter is not slowing it down so much?

This question is pretty straight forward but the answer I'm thinking is not ..

I have a query that runs fast - under a second. But If I pass many values to the filter criteria it slows down a great deal.

For example, it runs fast like this:

SELECT * FROM MYTABLE
WHERE DATE_COLUMN > TRUNC(SYSDATE-30)

But this same code runs very slow if I make the following addition:

SELECT * FROM MYTABLE
WHERE DATE_COLUMN > TRUNC(SYSDATE-30)
AND MYVALUE IN ('A', 'B', 'C', 'D', 'E')

Is there anything that can be done with the SQL to amend this. My goal is to have the query run fast, preferably under a second.

I have tried GROUP BY, but it did not make a difference.

I've ruled out all possibilities and the issue is with the IN (multiple values) section.

Any ideas?

This is too long for a comment.

How are you measuring the speed of the first query? One possibility is that you are measuring the speed to the first value being returned rather than the last value -- and Oracle finds it easy to returned values that meet the first condition. One way to check this is to use order by because this requires getting all the rows (and then doing more work):

SELECT *
FROM MYTABLE
WHERE DATE_COLUMN > TRUNC(SYSDATE-30)
ORDER BY othercol;

( ORDER BY would typically be processing all the data.)

Assuming you are not making that mistake, another potential problem is the use of indexes. Oracle is usually pretty good about this. And, you can use the execution plan to see if the execution plans are the same. For instance, you might have an index on date_column and one on myvalue . Oracle might choose the wrong index.

If this is the case, you can create an index on (myvalue, datecol) and trying running this query:

SELECT *
FROM MYTABLE
WHERE DATE_COLUMN > TRUNC(SYSDATE-30) AND
      MYVALUE = 'A';

If this runs fast, then try the index on your query. If that doesn't work, use UNION ALL :

SELECT *
FROM MYTABLE
WHERE DATE_COLUMN > TRUNC(SYSDATE-30) AND MYVALUE = 'A'
UNION ALL
SELECT *
FROM MYTABLE
WHERE DATE_COLUMN > TRUNC(SYSDATE-30) AND MYVALUE = 'B'
UNION ALL
. . .

1) find out the actual index being used for the 1st query (you may check the "explain plan"), then add a hint /*+index(MYTABLE MYINDEX)*/ to the 2nd SQL in order to ensure the same index is used for that as well

2) use the below SQL to force the sub-query to be processed first

SELECT * FROM (
  SELECT /*+no_merge*/ ROWNUM row_num, t.* FROM MYTABLE t
  WHERE DATE_COLUMN > TRUNC(SYSDATE-30)
) WHERE MYVALUE IN ('A', 'B', 'C', 'D', 'E')

I feel that whether a query is running faster or not can be checked by using explain plan to see what is happening internally. I would suggest:

  • Check explain plan of both the queries to see what is the difference in the way execution is happening.
  • There may be a possibility that there is no index on the myvalue column which is causing a hit in the performance of the query.
  • Anyways,much more can be said after seeing the actual explain plan of both the queries.

Hope this helps to narrow down the issue.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM