Calculate number of rows in an Oracle query - oracle

Is there a simple way to get the number of rows an Oracle SQL query returns?
I tried count in various ways but none worked. This seems to do the trick
SELECT ROWNUM, mv.*
FROM my_view mv
where col_a IS NOT NULL
order by ROWNUM desc
but is there something straightforward like nrow in R or .shape in Python?

SELECT count(*) over () as row_count, mv.*
FROM my_view mv
where col_a IS NOT NULL
will give you a count but unless you can be sure that performance is not going to be a problem, its generally a bad idea to do this. Because what if the table has 1 billion rows and you only need to show the first (say) 200 rows on screen? We are going to visit all the candidate rows in order to work out that count.
That's why a Google search says "Results 1..20 of ABOUT ..."

I was just wondering what the best practice would be to check the size of the view (...) I don't need to display the entire view, but only need to know the number of rows.
In that case, count(*) seems to be the way to do it. Pure & simple
SELECT count(*)
FROM my_view
WHERE col_a IS NOT NULL;
(You used order by clause; it promises to be slower than query without it.)
Alternatively, if it were a table (not a view), you could use a really fast option - query user_tables:
SQL> SELECT num_rows
2 FROM user_tables
3 WHERE table_name = 'EVID';
NUM_ROWS
----------
808757
How many rows does that table really have?
SQL> SELECT COUNT (*) FROM evid;
COUNT(*)
----------
808761
SQL>
Not exactly the same. Why? Because you should gather statistics:
SQL> EXEC DBMS_STATS.gather_table_stats('SJERV', 'EVID');
PL/SQL procedure successfully completed.
Now those values match:
SQL> SELECT num_rows
2 FROM user_tables
3 WHERE table_name = 'EVID';
NUM_ROWS
----------
808761
SQL>
It just means that you should regularly gather (schema) statistics - for example, on a daily basis. Then you'd have pretty much close information about number of rows. But, to be sure how many rows you really have, once again - select count(*).

Related

How can you check query performance with small data set

All the Oracles out here,
I have an Oracle PL/SQL procedure but very small data that can run on the query. I suspect that when the data gets large, the query might start performing back. Are there ways in which I can check for performance and take corrective measure even before the data build up? If I wait for the data buildup, it might get too late.
Do you have any general & practical suggestions for me? Searching the internet did not get me anything convincing.
Better to build yourself some test data to get an idea of how things will perform. Its easy to get started, eg
create table MY_TEST as select * from all_objects;
gives you approx 50,000 rows typically. You can scale that easily with
create table MY_TEST as select a.* from all_objects a ,
( select 1 from dual connect by level <= 10);
Now you have 500,000 rows
create table MY_TEST as select a.* from all_objects a ,
( select 1 from dual connect by level <= 10000);
Now you have 500,000,000 rows!
If you want unique values per row, then add rownum eg
create table MY_TEST as select rownum r, a.* from all_objects a ,
( select 1 from dual connect by level <= 10000);
If you want (say) 100,000 distinct values in a column then TRUNC or MOD. You can also use DBMS_RANDOM to generate random numbers, strings etc.
Also check out Morten's test data generator
https://github.com/morten-egan/testdata_ninja
for some domain specific data, and also the Oracle sample schemas on github which can also be scaled using techniques above.
https://github.com/oracle/db-sample-schemas

Performance issue with IN clause

I have question for using IN clause in sql query which of the following provide better performance
SELECT * FROM emp WHERE deptno IN (10,20)
OR
WITH dep AS (SELECT 10 deptno FROM DUAL UNION ALL
SELECT 20 deptno FROM DUAL)
SELECT * FROM EMP e
WHERE EXISTS (SELECT 1 FROM dep WHERE dep.deptno=e.deptno);
I am looking which will provide better performance
"In clause" will be better choice because in another example optimizer can't figure out how to join this two tables so it scans all of the emp table and see if particularly record meets your condition. I've checked this on huge table (more than million rows) and the query plan was very different. Of course I assumed that you have index on deptno column. Without it both solutions require full table scan on emp table.

How do I get the number of rows in each table I have in my oracle database

Can someone tell me how I can get the number of rows in each table in my oracle database? I have found several queries, but none of them worked because I am using oracle 7 and sqlplus 3.2 and basically all what I found didn't work on it. I just need something that would work on sqlplus 3.2.
Required:
Table Name Rows
Table 1 0
Table 2 5
...
Is it possible to do it with something like a loop? Or what exactly should I do?
if SELECT table_name, num_rows from all_tables doesn't give you what you need.
You could use dynamic SQL and counts as Rahul selected.
Run the below to get results which dynamically build a union on all tables, then run the results as it's own query to get final results.
SELECT 'SELECT ' ||t.name || ' as tName, count(*) as Row_Cnt
FROM ' || t.name || ' UNION ALL '
FROM ALL_TABLES t
Just be sure to remove the last union statement on the last query.
Also note: if you don't have access to see the table, it will not come out in this list!
---Updated ------
So if all_tables doesn't exist none of this will work. Since I don't have a oracle 7 instance handy... could you see if SELECT * FROM dictionary returns anything that might produce a list of all the tables? If you find a view or table object use it in place of all_tables above.
I'm reading the docs for oracle 7 now but finding little easily searchable. thus a guess and check method may go faster.

A fast query that selects the number of rows in each table

I want a query that selects the number of rows in each table
but they are NOT updated statistically .So such query will not be accurate:
select table_name, num_rows from user_tables
i want to select several schema and each schema has minimum 500 table some of them contain a lot of columns . it will took for me days if i want to update them .
from the site ask tom he suggest a function includes this query
'select count(*)
from ' || p_tname INTO l_columnValue;
such query with count(*) is really slow and it will not give me fast results.
Is there a query that can give me how many rows are in table in a fast way ?
You said in a comment that you want to delete (drop?) empty tables. If you don't want an exact count but only want to know if a table is empty you can do a shortcut count:
select count(*) from table_name where rownum < 2;
The optimiser will stop when it reaches the first row - the execution plan shows a 'count stopkey' operation - so it will be fast. It will return zero for an empty table, and one for a table with any data - you have no idea how much data, but you don't seem to care.
You still have a slight race condition between the count and the drop, of course.
This seems like a very odd thing to want to do - either your application uses the table, in which case dropping it will break something even if it's empty; or it doesn't, in which case it shouldn't matter whether it has (presumably redundant) and it can be dropped regardless. If you think there might be confusion, that sounds like your source (including DDL) control needs some work, maybe?
To check if either table in two schemas have a row, just count from both of them; either with a union:
select max(c) from (
select count(*) as c from schema1.table_name where rownum < 2
union all
select count(*) as c from schema2.table_name where rownum < 2
);
... or with greatest and two sub-selects, e.g.:
select greatest(
(select count(*) from schema1.table_name where rownum < 2),
(select count(*) from schema2.table_name where rownum < 2)
) from dual;
Either would return one if either table has any rows, and would only return zero f they were both empty.
Full Disclosure: I had originally suggested a query that specifically counts a column that's (a) indexed and (b) not null. #AlexPoole and #JustinCave pointed out (please see their comments below) that Oracle will optimize a COUNT(*) to do this anyway. As such, this answer has been altered significantly.
There's a good explanation here for why User_Tables shouldn't be used for accurate row counts, even when statistics are up to date.
If your tables have indexes which can be used to speed up the count by doing an index scan rather than a table scan, Oracle will use them. This will make the counts faster, though not by any means instantaneous. That said, this is the only way I know to get an accurate count.
To check for empty (zero row) tables, please use the answer posted by Alex Poole.
You could make a table to hold the counts of each table. Then, set a trigger to run on INSERT for each of the tables you're counting that updates the main table.
You'd also need to include a trigger for DELETE.

where rownum=1 query taking time in Oracle

I am trying to execute a query like
select * from tableName where rownum=1
This query is basically to fetch the column names of the table.There are more than million records in the table.When I put the above condition its taking so much time to fetch the first row.Is there any alternate to get the first row.
This question has already been answered, I will just provide an explanation as to why sometimes a filter ROWNUM=1 or ROWNUM <= 1 may result in a long response time.
When encountering a ROWNUM filter (on a single table), the optimizer will produce a FULL SCAN with COUNT STOPKEY. This means that Oracle will start to read rows until it encounters the first N rows (here N=1). A full scan reads blocks from the first extent to the high water mark. Oracle has no way to determine which blocks contain rows and which don't beforehand, all blocks will therefore be read until N rows are found. If the first blocks are empty, it could result in many reads.
Consider the following:
SQL> /* rows will take a lot of space because of the CHAR column */
SQL> create table example (id number, fill char(2000));
Table created
SQL> insert into example
2 select rownum, 'x' from all_objects where rownum <= 100000;
100000 rows inserted
SQL> commit;
Commit complete
SQL> delete from example where id <= 99000;
99000 rows deleted
SQL> set timing on
SQL> set autotrace traceonly
SQL> select * from example where rownum = 1;
Elapsed: 00:00:05.01
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=7 Card=1 Bytes=2015)
1 0 COUNT (STOPKEY)
2 1 TABLE ACCESS (FULL) OF 'EXAMPLE' (TABLE) (Cost=7 Card=1588 [..])
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
33211 consistent gets
25901 physical reads
0 redo size
2237 bytes sent via SQL*Net to client
278 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
As you can see the number of consistent gets is extremely high (for a single row). This situation could be encountered in some cases where for example, you insert rows with the /*+APPEND*/ hint (thus above high water mark), and you also delete the oldest rows periodically, resulting in a lot of empty space at the beginning of the segment.
Try this:
select * from tableName where rownum<=1
There are some weird ROWNUM bugs, sometimes changing the query very slightly will fix it. I've seen this happen before, but I can't reproduce it.
Here are some discussions of similar issues: http://jonathanlewis.wordpress.com/2008/03/09/cursor_sharing/ and http://forums.oracle.com/forums/thread.jspa?threadID=946740&tstart=1
Surely Oracle has meta-data tables that you can use to get column names, like the sysibm.syscolumns table in DB2?
And, after a quick web search, that appears to be the case: see ALL_TAB_COLUMNS.
I'd use those rather than go to the actual table, something like (untested):
SELECT COLUMN_NAME
FROM ALL_TAB_COLUMNS
WHERE TABLE_NAME = "MYTABLE"
ORDER BY COLUMN_NAME;
If you are hell-bent on finding out why your query is slow, you should revert to the standard method: asking your DBMS to explain the execution plan of the query for you. For Oracle, see section 9 of this document.
There's a conversation over at Ask Tom - Oracle that seems to suggest the row numbers are created after the select phase, which may mean the query is retrieving all rows anyway. The explain will probably help establish that. If it contains FULL without COUNT STOPKEY, then that may explain the performance.
Beyond that, my knowledge of Oracle specifics diminishes and you will have to analyse the explain further.
Your query is doing a full table scan and then returning the first row.
Try
SELECT * FROM table WHERE primary_key = primary_key_value;
The first row, particularly as it pertains to ROWNUM, is arbitrarily decided by Oracle. It may not be the same from query to query, unless you provide an ORDER BY clause.
So, picking a primary key value to filter by is as good a method as any to get a single row.
I think you're slightly missing the concept of ROWNUM - according to Oracle docs: "ROWNUM is a pseudo-column that returns a row's position in a result set. ROWNUM is evaluated AFTER records are selected from the database and BEFORE the execution of ORDER BY clause."
So it returns ANY row that it consideres #1 in the result set which in your case will contain 1M rows.
You may want to check out a ROWID pseudo-column: http://psoug.org/reference/pseudocols.html
I've recently had the same problem you're describing: I want one row from the very large table as a quick, dirty, simple introspection, and "where rownum=1" alone behaves very poorly. Below is a remedy which worked for me.
Select the max() of the first term of some index, and then use it to choose some small fraction of all rows with "rownum=1". Suppose my table has some index on numerical "group-id", and compare this:
select * from my_table where rownum = 1;
-- Elapsed: 00:00:23.69
with this:
select * from my_table where rownum = 1
and group_id = (select max(group_id) from my_table);
-- Elapsed: 00:00:00.01

Resources