• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 11162
  • Last Modified:

Count Total Records Using PL/SQL

Hi,
 I have a query that returns about 100,000 records in about .2 seconds. However, I need to return the count(*) of these records, and that takes about 17 seconds. I have tried various sql approaches

(see this thread:
 http://www.experts-exchange.com/Database/Oracle/Q_22995116.html)

and I am already implementing those suggestions, and it still take 17 seconds. I have also written the follow proc, which, annoyingly, takes exactly the same amount of time to complete. It appears the even using bulk collect, it takes 17 seconds to get the records from the cursor, even though i'm only retrieving a single column, which is just numbers (and that column is indexed).

is there ANY faster way to do this?
create or replace
PROCEDURE COUNTER AS
 
TYPE v_array is varray(100000) of NUMBER(38,8); 
temp_array V_ARRAY;
 
CURSOR nwr is SELECT x_coord from GRID_FLORIDA g,f_region r where r.region_id = 'R108' and sdo_relate(g.geom, r.geom,'mask=ANYINTERACT querytype=WINDOW') = 'TRUE';
 
begin 
open nwr;
  fetch nwr bulk collect into temp_array;
  Dbms_output.PUT_LINE(temp_array.count);
close nwr;
END COUNTER;

Open in new window

0
chrismarx
Asked:
chrismarx
  • 9
  • 7
  • 4
  • +4
2 Solutions
 
yuchingCommented:
what's the function sdo_relate actually doing?
0
 
chrismarxAuthor Commented:
its oracle spatial sql
0
 
yuchingCommented:
Sorry chrismarx:, i doesnt know anything about sdo_relate. However, found this documents on the web http://download-uk.oracle.com/docs/cd/B10501_01/appdev.920/a96630/sdo_operat.htm#i78531 -->
Refer usage note for sdo_relate
Hope this help, :)
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
chrismarxAuthor Commented:
its possible that this situation is related to the spatial expression used here, but i highly doubt it. what i need is a way to speed up the pl/sql proc
0
 
sujith80Commented:
>> I have a query that returns about 100,000 records in about .2 seconds

How did you measure this time?
0
 
chrismarxAuthor Commented:
its a good question. that's the time it took (using sql developer/toad) for the query "finish", as in you can start viewing the records -
0
 
sujith80Commented:
>> as in you can start viewing the records
Yes, there's the problem. You star seeing the records doesn't mean that it has fetched all the records. You try to scroll down through the records. You can see the scrollbar hanging for some time to retrieve the next set of records. So, I believe the 17 seconds is the time it takes to retrieve the records and the count(*) DID NOT make any difference.
0
 
schwertnerCommented:
This is an old trick used to check if the DBA is smart enough.
I gues you have either  no or old statistics over the table (database).
To get the statistics ask the DBA to run the statistics and to schedule
this process for running periodically:

 
/*
** To run automatically statistics computing on
** middnight today and every week after that also on middnight
** run in SQL*Plus as user SYS the following script
** Write down the number returned by the script.
** It should be used to point the queued job
** for operations like delete, reschedule, etc.
** when using the DBMS_JOB package
*/ 
 
 
CREATE OR REPLACE PROCEDURE compute_statistics IS
BEGIN 
   dbms_stats.gather_database_stats(cascade=>true);
END compute_statistics;
/
 
 
set serveroutput on
set linesize 10000
variable x number;
begin 
   DBMS_OUTPUT.enable(100000);   
   dbms_job.submit(:x,'compute_statistics;',trunc(sysdate),'trunc(sysdate+7)'); 
   commit;
   dbms_output.put_line(TO_char(:x));
end;
/

Open in new window

0
 
anand_2000vCommented:
Why are you not using nwr%rowcount ?
0
 
anand_2000vCommented:

create or replace
PROCEDURE COUNTER AS
 
TYPE v_array is varray(100000) of NUMBER(38,8); 
temp_array V_ARRAY;
 
CURSOR nwr is SELECT x_coord from GRID_FLORIDA g,f_region r where r.region_id = 'R108' and sdo_relate(g.geom, r.geom,'mask=ANYINTERACT querytype=WINDOW') = 'TRUE';
 
begin 
open nwr;
  Dbms_output.PUT_LINE(nwr%rowcount);
close nwr;
END COUNTER;

Open in new window

0
 
anand_2000vCommented:
or maybe faster
create or replace
PROCEDURE COUNTER AS
 
TYPE v_array is varray(100000) of NUMBER(38,8); 
temp_array V_ARRAY;
 
CURSOR nwr is SELECT x_coord from GRID_FLORIDA g,f_region r where r.region_id = 'R108' and sdo_relate(g.geom, r.geom,'mask=ANYINTERACT querytype=WINDOW') = 'TRUE';
 
begin 
open nwr;
null;
close nwr;
  Dbms_output.PUT_LINE(nwr%rowcount);
END COUNTER;

Open in new window

0
 
chrismarxAuthor Commented:
that returns 0, im assuming since no rows have actually been fetched...

schwertner:
i actually ran both these statements yesterday, thinking it could speed things up a bit

analyze table "OWNER"."GRID_FLORIDA" VALIDATE structure

begin
                DBMS_STATS.GATHER_TABLE_STATS (
                  ownname => 'OWNER',
          tabname => 'GRID_FLORIDA',
          estimate_percent => 20
          );
          end;


and it did seem to make a small improvment, its around 16 seconds now... do you want to see the stats, would that help diagnosis?
0
 
anand_2000vCommented:
my mistake..Seeing my code now, I wonder whether I was sleeping when I wrote that.
have you analyzed your PRIMARY KEY columns? is the table static or changes occur to it?
I would still go for regular count(*) or count(primary key column)
0
 
Jinesh KamdarCommented:
@chrismarx - Did you try to fire the SELECT with COUNT() in TOAD outside of the PL/SQL block?
Did it return any faster than 17 seconds?

SELECT COUNT(x_coord) from GRID_FLORIDA g,f_region r
where r.region_id = 'R108' and
sdo_relate(g.geom, r.geom,'mask=ANYINTERACT querytype=WINDOW') = 'TRUE';
0
 
ajexpertCommented:
Hi,
I would suggest to provide an explain plan for the query in curosr.
If its using full table scan and not using index paths, use index hints.

Hope this helps
ajexpert
0
 
chrismarxAuthor Commented:
@jinesh_kamdar:

yeah, its pretty much exactly the same.

@ajexpert:
explain plan below-
what kind of index hints were you thinking of?
/* explain plan */
 
"Optimizer"	"Cost"	"Cardinality"	"Bytes"	"Partition Start"	"Partition Stop"	"Partition Id"	"ACCESS PREDICATES"	"FILTER PREDICATES"
"SELECT STATEMENT"	"CHOOSE"	"7404.530391041"	"25090"	"98854600"	""	""	""	""	""
"NESTED LOOPS"	""	"7404.530391041"	"25090"	"98854600"	""	""	""	""	""
"TABLE ACCESS(BY INDEX ROWID) F_REGION"	""	"1"	"1"	"3885"	""	""	""	""	""
"INDEX(RANGE SCAN) PK_REGION_REGION_ID"	""	"1"	"1"	""	""	""	""	""	""
"TABLE ACCESS(BY INDEX ROWID) GRID_FLORIDA"	"ANALYZED"	"7404.530391041"	"30597"	"1682835"	""	""	""	""	""
"DOMAIN INDEX GEOMETRY_IX1"	

Open in new window

0
 
Jinesh KamdarCommented:
>> yeah, its pretty much exactly the same.
Fetching the COUNT() cannot take more time than the fetching the actual record-set. So you can safely conclude that all the 100,000 records do not return in just 0.02 seconds.
0
 
chrismarxAuthor Commented:
yes, as i said, i agree.  so it appears that trying to optimize the query itself is the only other solution?
before we get to that, i've noticed that when i change the id in the where clause, the proc can take minutes to return the answer when first run (im assuming some kind of compile?). i rewrote the proc to use a argument as the id, thinking that would act as a bind variable, but it still takes much longer to complete each time i pass in a different id-
0
 
anand_2000vCommented:
I see that you are accessing 30597 records of GRID_FLORIDA table. That by itself should not cause 16 seconds. What is this sdo_relate doing? Can you not do the operation directly?
0
 
chrismarxAuthor Commented:
sdo_relate is the spatial function that determines whether the polygon geometries in the grid_florida table are either touching/intersecting the single polygon that is being retrieved from the region table. i dont believe there is any other way to do this in a spatially explicit fashion-
0
 
Jinesh KamdarCommented:
>> SELECT x_coord from GRID_FLORIDA g,f_region r where r.region_id = 'R108' and sdo_relate(g.geom, r.geom,'mask=ANYINTERACT querytype=WINDOW') = 'TRUE';
 
Do you think ur missing any join condition here between the "grid_florida" and "f_region" tables or this is the way it is supposed to be written?
0
 
chrismarxAuthor Commented:
re-writing the query as below is equivalent-
SELECT count(*) from
GRID_FLORIDA g
join f_region r on
sdo_relate(g.geom, r.geom,'mask=ANYINTERACT
querytype=WINDOW') = 'TRUE'
where r.region_id = 'R117'

Open in new window

0
 
Jinesh KamdarCommented:
No, what i meant is that - Is there any relation between those 2 tables by way of foreign-key or otherwise? Is the below valid join condition for them? Post ur table structures for more clarity.

where r.geom = g.geom
0
 
chrismarxAuthor Commented:
i can post the table structure, but im not sure you understand what sdo_relate is doing. there is no foreign key here, there is a geometry object in the f_region (a large polygon covering a wide span of florida) and rather small grid squares (also polygons, but covering all of florida) in the grid_florida table. the query finds where there is interaction between the 2 sets of geometric object.

please let me know if you still want to see the table structures-
0
 
schwertnerCommented:
----> i've noticed that when i change the id in the where clause, the proc can take minutes to return the answer when first run (im assuming some kind of compile?).

This is evidence that you have NO statistics over the table or other issue.

Pay attention to "cascade=>true' in my code.
This forces to analyze ALSO all table indexes.

Be aware that if there is no statistics, the Optimizer takes Full Table Scan,
reading all records in the DB_Blocks_Buffer_Cache and this explains why you need
minutes to get the first result. After that the majority of the blocks are in the cache
and of course the decreased numbers of Disk I/O leads to faster select.

0
 
anand_2000vCommented:
>>Be aware that if there is no statistics, the Optimizer takes Full Table Scan,

IMHO, if there are no statistics, Oracle Choose optimizer mode will go for RBO. Which will mean that in a given situation Index access will be preferred.
0
 
schwertnerCommented:
RBO is depricated.
0
 
anand_2000vCommented:
RBO still exists in Oracle 10g, but it is an unsupported feature. Oracle declares that no code changes will be made to RBO and no bug fixes will be provided.
Oracle 10g Oracle10g Optimizer Mode

CHOOSE and RULE are no longer supported as optimizer_mode initialization parameter values. If you set up any of these parameters, a warning is displayed in the alert log. The functionalities of those parameter values still exist but will be removed in a future release. Now, for 10g, all_rows is the default value for the optimizer_mode initialization parameter.
0

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

  • 9
  • 7
  • 4
  • +4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now