Query Execution takes more time in bitmap index - sql

My table has 1 million records. I want to fetch only the inactive user from the table. The query execution takes more than 10 minutes. Even though I am
using index.
STATUS has only two values Either Y or N. So i have created the bitmap index for that column.
EXPLAIN PLAN FOR
SELECT CUSTOMER NAME,MOBILE NUMBER,ACCOUNT NUMBER,CUSTOMER ID,REGISTARTION DATE from REGISTRATION where STATUS='N';
Plan hash value: 2615581521
---------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
---------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 960K| 66M| 9880 (1)| 00:01:59 | | |
| 1 | PARTITION RANGE ALL | | 960K| 66M| 9880 (1)| 00:01:59 | 1 |1048575|
| 2 | PARTITION HASH ALL | | 960K| 66M| 9880 (1)| 00:01:59 | 1 | 4 |
| 3 | TABLE ACCESS BY LOCAL INDEX ROWID| REGISTRATION | 960K| 66M| 9880 (1)| 00:01:59 | 1 |1048575|
| 4 | BITMAP CONVERSION TO ROWIDS | | | | | | | |
|* 5 | BITMAP INDEX SINGLE VALUE | IDX_REGISTRATION_7 | | | | | 1 |1048575|
---------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
5 - access("STATUS"='N')
Note
-----
- dynamic sampling used for this statement (level=11)
-----------------------------------------------------------------------------------------------------------------------------------------------------
How to improve the performance of the above query?

Related

Oracle performance lowered by using parenthesis

I've read this: Parenthesis() and SQL Query Performance
I have posted this: Oracle not using indexes if queried in wrong order
What we are experiencing right now is beyond my understanding, and I am asking for explanation.
Query:
SELECT * FROM PREMIUMACCOUNTBOOKING p WHERE PARENTFOREIGNKEY = 499699430 AND CLASSID = 511 ORDER BY BOOKINGNO;
lasts 3 ms.
Explanation plan:
Plan hash value: 3357352015
------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4 | 632 | 9 (12)| 00:00:01 |
| 1 | SORT ORDER BY | | 4 | 632 | 9 (12)| 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID BATCHED| PREMIUMACCOUNTBOOKING | 4 | 632 | 8 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | PREMIUMACCOUNTBOOKI_511_2 | 4 | | 4 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("PARENTFOREIGNKEY"=499699430 AND "CLASSID"=511)
Now, query SELECT * FROM PREMIUMACCOUNTBOOKING WHERE PARENTFOREIGNKEY=499699430 AND (CLASSID=511) ORDER BY BOOKINGNO;
lasts 40 seconds! Repeatedly. No improvement even after several executions.
Explanation plan:
Plan hash value: 3357352015
------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4 | 632 | 9 (12)| 00:00:01 |
| 1 | SORT ORDER BY | | 4 | 632 | 9 (12)| 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID BATCHED| PREMIUMACCOUNTBOOKING | 4 | 632 | 8 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | PREMIUMACCOUNTBOOKI_511_2 | 4 | | 4 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("PARENTFOREIGNKEY"=499699430 AND "CLASSID"=511)
I do not see any difference, except in actual execution time.
What can I do to identify the reason for this behaviour?
Thank you,
GG

Improving the query processing performance of SUM and JOIN SQL

SELECT SUM(C_QUANTITY)
FROM CARS JOIN ORDERS
ON C_ORDERKEY = O_ORDERKEY;
I have this query that aggregate sum of L_QUANTITY from the JOIN tables. The query cost, by using EXPLAIN PLAN is 12147. The objective is to improve this SELECT statement by implementing a more efficient SELECT statement that will get the same result.
I have tried
SELECT SUM(C_QUANTITY)
FROM CARS
It returned the same result but the query cost is exactly the same as the original. I thought that by removing the JOIN, the SELECT query will improve.
Is there a way to reduce the cost by simply modify the SELECT statement only?
Edit:
Original query plan
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 2287326370
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 3 | 12147 (1)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 3 | | |
| 2 | TABLE ACCESS FULL| CARS | 1800K| 5273K| 12147 (1)| 00:00:01 |
-------------------------------------------------------------------------------
9 rows selected.
With the second query
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 2287326370
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 3 | 12147 (1)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 3 | | |
| 2 | TABLE ACCESS FULL| CARS | 1800K| 5273K| 12147 (1)| 00:00:01 |
-------------------------------------------------------------------------------
9 rows selected.
If you have two table cars and ordersthat are not connected, you will get and ordinary join execution plan as follows.
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 15 | | 297 (2)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 15 | | | |
|* 2 | HASH JOIN | | 100K| 1464K| 1664K| 297 (2)| 00:00:01 |
| 3 | TABLE ACCESS FULL| ORDERS | 100K| 488K| | 47 (3)| 00:00:01 |
| 4 | TABLE ACCESS FULL| CARS | 100K| 976K| | 62 (2)| 00:00:01 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("C_ORDERKEY"="O_ORDERKEY")
The table cars is apparently a child table or the orders, i.e. you have this constraints
alter table orders add primary key (O_ORDERKEY);
alter table cars add constraint cars_fk foreign key(C_ORDERKEY) references orders(O_ORDERKEY);
Oracle is smart enough to know it does not need to access the orders table to get the sum
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 10 | 63 (4)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 10 | | |
|* 2 | TABLE ACCESS FULL| CARS | 100K| 976K| 63 (4)| 00:00:01 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("C_ORDERKEY" IS NOT NULL)
Note the filter C_ORDERKEY IS NOT NULL which is still required to get the right sum if the column C_ORDERKEY is nullable. (Those rows would be eliminated in the join).
In case it is not, which may be meaningfull
alter table cars modify C_ORDERKEY not null;
you only need to define an index on the C_QUANTITY column to get the optimal plan
create index car_idx on cars(C_QUANTITY);
---------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 5 | 63 (2)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 5 | | |
| 2 | INDEX FAST FULL SCAN| CAR_IDX | 100K| 488K| 63 (2)| 00:00:01 |
---------------------------------------------------------------------------------
Note that the INDEX FAST FULL SCAN uses the index in a kind as a table full scan access (i.e. without direct accessing the index block using the pointers) so it is (in case that the index is smaller than the table) much faster that the table full scan access.
I suggest adding the following index:
CREATE INDEX idx ON ORDERS (O_ORDERKEY, C_QUANTITY);
Presumably, the ORDERS table would be much larger than CARS. If so, Oracle would likely satisfy the query by scanning CARS and then would be able to use the above index to lookup in the ORDERS table. I add the C_QUANTITY column to the end of the index, to cover the summation in the select clause.

Slow inner join in Oracle

I have Oracle database with a main table contain 9 000 000 rows and a second with 19 000 000 rows.
When I do :
SELECT *
FROM main m
INNER JOIN second s ON m.id = s.fk_id AND s.cd = 'E' AND s.line = 1
It's take 45 seconds to get the first part of the result, even with all the index below :
CREATE INDEX IDX_1 ON SECOND (LINE, CD, FK_ID, ID);
CREATE INDEX IDX_1 ON SECOND (LINE, CD);
MAIN (ID) AS PRIMARY KEY
Any idea how to do it faster ? I try some index, rebuild but it's always take 45 seconds
Here is the execution plan :
------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost | Time |
------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 8850631 | 2133002071 | 696494 | 00:00:28 |
| * 1 | HASH JOIN | | 8850631 | 2133002071 | 696494 | 00:00:28 |
| * 2 | TABLE ACCESS FULL | SECOND | 8850631 | 646096063 | 143512 | 00:00:06 |
| 3 | TABLE ACCESS FULL | MAIN | 9227624 | 1550240832 | 153363 | 00:00:06 |
------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
------------------------------------------
* 1 - access("M"."ID"="S"."FK_ID")
* 2 - filter("S"."CD"='D' AND "S"."LINE"=1)
Thanks
If you want to see the first line quickly you have to enable Oracle to use the NESTED LOOP join.
This will required an index on second with the two columns you constraint in your query and an index on main on the join column id
create index second_idx on second(line,cd);
create index main_idx on main(id);
You'll see an execution plan similar to one below
--------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 87 | 8178 | 178 (0)| 00:00:03 |
| 1 | NESTED LOOPS | | | | | |
| 2 | NESTED LOOPS | | 87 | 8178 | 178 (0)| 00:00:03 |
| 3 | TABLE ACCESS BY INDEX ROWID| SECOND | 87 | 2523 | 4 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | SECOND_IDX | 1 | | 3 (0)| 00:00:01 |
|* 5 | INDEX RANGE SCAN | MAIN_IDX | 1 | | 1 (0)| 00:00:01 |
| 6 | TABLE ACCESS BY INDEX ROWID | MAIN | 1 | 65 | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("S"."LINE"=1 AND "S"."CD"='E')
5 - access("M"."ID"="S"."FK_ID")
You will access via index all rows in second with requested lineand cd (plan line 4 and 3) and for each such row you'll access via index the main table (lines 5 and 6)
This will provide an instant access to the first few rows and will work fine if there are a low number of rows in second table with the selected line and cd. In other case (when there is a large number of rows with s.cd = 'E' AND s.line = 1 - say 10k+) you will still see the first result rows quickly, but you'll wait ages to see the last row (it will take much more that the 45 seconds to finish the query).
If this is a problem you have to use a HASH JOIN (which you probaly do now).
A hash join typically doesn not use indexes and produced following execution plan
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 10182 | 1153K| 908 (1)| 00:00:11 |
|* 1 | HASH JOIN | | 10182 | 1153K| 908 (1)| 00:00:11 |
|* 2 | TABLE ACCESS FULL| SECOND | 10182 | 99K| 520 (2)| 00:00:07 |
| 3 | TABLE ACCESS FULL| MAIN | 90000 | 9316K| 387 (1)| 00:00:05 |
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("M"."ID"="S"."FK_ID")
2 - filter("S"."LINE"=1 AND "S"."CD"='E')
Summary
To use the nested loops the indexes must be available as described above
The switch between nested loopsand hash join is done by the Oracle database (CBO) - provided that your tables statistics and database configuration are fine.

Is it better to use sql hint /*+ opt_param('_optimizer_use_feedback' 'false') */ in the select statement

The execution plan:
Plan 1:
--------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 9 (100)| |
| 1 | TABLE ACCESS BY INDEX ROWID| EMP_HISTORY | 1 | 190 | 9 (0)| 00:00:01 |
| 2 | INDEX RANGE SCAN | IND_EMP_HISTORY_VALDT | 15 | | 4 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------------
Plan 2:
------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 281 (100)| |
| 1 | TABLE ACCESS BY INDEX ROWID| EMP_HISTORY | 3 | 570 | 281 (0)| 00:00:04 |
| 2 | INDEX RANGE SCAN | IND_EMP_HISTORY_EMPNO | 1203 | | 6 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------------
I did for first plan1 by disabling the setting parameter "_OPTIMIZER_USE_FEEDBACK" = FALSE at database level, but this is not suitable because it may effect other query.For second paln the sql hint /*+ opt_param('_optimizer_use_feedback' 'false') */ used in select statement.
Could anyone please advice.
Thanks,
Raju

An oracle performance issue on COUNT()

I'm using Oracle 11g, the main table has about 10m records. Here is my query:
SELECT COUNT (*)
FROM CONTACT c INNER JOIN STATUS S ON C.STATUS = S.STATUS
WHERE C.USER = 1 AND S.REQUIRE = 1 AND ROWNUM = 1;
The Cost is 3736, but when I changed it to this form:
SELECT COUNT (*) FROM
(SELECT 1 FROM CONTACT c INNER JOIN STATUS S ON C.STATUS = S.STATUS
WHERE C.USER = 1 AND S.REQUIRE = 1 AND ROWNUM = 1);
The Cost became 5! What's the difference between these 2 queries?
Here are the explain plan for both query:
The first query:
----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 10 | 3736 (1)| 00:00:45 |
| 1 | SORT AGGREGATE | | 1 | 10 | | |
|* 2 | COUNT STOPKEY | | | | | |
| 3 | NESTED LOOPS | | 4627 | 46270 | 3736 (1)| 00:00:45 |
| 4 | TABLE ACCESS BY INDEX ROWID| CONTACT | 6610 | 33050 | 3736 (1)| 00:00:45 |
|* 5 | INDEX RANGE SCAN | IX_CONTACT_USR | 6610 | | 20 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | IX_CONTACT_STATUS | 1 | 5 | 0 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(ROWNUM=1)
5 - access("C"."USER"=1)
6 - access("C"."STATUS"="S"."STATUS" AND "S"."REQUIRE"=1)
The second query:
-----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 5 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | | | |
| 2 | VIEW | | 1 | | 5 (0)| 00:00:01 |
|* 3 | COUNT STOPKEY | | | | | |
| 4 | NESTED LOOPS | | 2 | 20 | 5 (0)| 00:00:01 |
| 5 | TABLE ACCESS BY INDEX ROWID| CONTACT | 3 | 15 | 5 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | IX_CONTACT_USR | 6610 | | 3 (0)| 00:00:01 |
|* 7 | INDEX RANGE SCAN | IX_CONTACT_STATUS | 1 | 5 | 0 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter(ROWNUM=1)
6 - access("C"."USER"=1)
7 - access("C"."STATUS"="S"."STATUS" AND "S"."REQUIRE"=1)
I executed 2 queries, the first one sometimes cost 45s+ (e.g. first run or change the user id), otherwise it will cost <1s. I totally don't know why it's such different, maybe db cache?
When I executed the second query, I can always get result in 1s. So I think the second one is better, but I don't the reason why it improves a lot.
You can see where the difference comes in by comparing the line in the execution plans that access the CONTACT table (looks at the rows column, the first one).
First:
| 4 | TABLE ACCESS BY INDEX ROWID| CONTACT | 6610 | 33050 | 3736 (1)| 00:00:45 |
Second:
| 5 | TABLE ACCESS BY INDEX ROWID| CONTACT | 3 | 15 | 5 (0)| 00:00:01 |
In the first example, the ROWNUM = 1 predicate isn't applied until after the CONTACT table has been accessed, so you're getting 6610 rows returned from this table. Whereas in your second query optimizer has only returned 3. This is many orders of magnitude less, which is why you're seeing the second query complete quicker.
As to why the second execution of the "slow" query is "fast", you're thinking is correct - the data has been loaded from disk into the buffer cache so access is much quicker.
Most likely that's just estimation difference and they will have same execution statistics. Trace both + tkprof to get real data.
Also if you want some more details behind optimizer logic - do hard parse with event 10053.
Cost is not only the factor for the queries, some times it depends on the server also, which u r showing is it a CPU cost or I/O Cost, some times cost my vary, because of the Column Cardinality, Conditions of the query. if u wanna see the much clarification on the queries, get the explain plan or TKPROOF, so that u 'll get to know , it's going for full table scan or which index is picking up and execution time.