According to the documentation NUM_ROWS is the "Number of rows in the table", so I can see how this might be confusing. There, however, is a major difference between these two methods.
This query selects the number of rows in MY_TABLE from a system view. This is data that Oracle has previously collected and stored.
select num_rows from all_tables where table_name = 'MY_TABLE'
This query counts the current number of rows in MY_TABLE
select count(*) from my_table
By definition they are difference pieces of data. There are two additional pieces of information you need about NUM_ROWS.
In the documentation there's an asterisk by the column name, which leads to this note:
Columns marked with an asterisk (*) are populated only if you collect statistics on the table with the ANALYZE statement or the DBMS_STATS package.
This means that unless you have gathered statistics on the table then this column will not have any data.
Statistics gathered in 11g+ with the default estimate_percent
, or with a 100% estimate, will return an accurate number for that point in time. But statistics gathered before 11g, or with a custom estimate_percent
less than 100%, uses dynamic sampling and may be incorrect. If you gather 99.999% a single row may be missed, which in turn means that the answer you get is incorrect.
If your table is never updated then it is certainly possible to use ALL_TABLES.NUM_ROWS to find out the number of rows in a table. However, and it's a big however, if any process inserts or deletes rows from your table it will be at best a good approximation and depending on whether your database gathers statistics automatically could be horribly wrong.
Generally speaking, it is always better to actually count the number of rows in the table rather then relying on the system tables.