Hello all.  I am looking for a fast way to find out the number of rows in a
table.  

I am hoping for something faster than "select count(*) from X", which can
sometimes take a bit too long for me.  On one 2-million-row table of mine,
it takes 17 seconds on my machine.  Maybe I'm greedy, but I had an idea that
I could get the row count with DatabaseMetaData.getIndexInfo() instead (and
hopefully this would be faster than "select count(*) from X").  But
unfortunately the data returned by getIndexInfo() are not filling the bill.

The javadocs for java.sql.DatabaseMetaData.getIndexInfo() state:
"CARDINALITY int => When TYPE is tableIndexStatistic, then this is the
number of rows in the table...."

(http://java.sun.com/j2se/1.5.0/docs/api/java/sql/DatabaseMetaData.html#getI
ndexInfo(java.lang.String,%20java.lang.String,%20java.lang.String,%20boolean
,%20boolean))

And that is the nugget that I am after.  But Derby's
DatabaseMetaData.getIndexInfo() seems never to return a row with TYPE ==
DatabaseMetaData.tableIndexStatistic.  The following program (which produced
the same results on Derby 10.4.1.3 and 10.3.1.4) shows what I mean:

import java.sql.*;
public class GetNumberOfRowsViaMetaData {
        static public void main(String args_[]) throws Exception {
                Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
                String url =
"jdbc:derby:testDatabase-"+System.currentTimeMillis();
                Connection conn =
DriverManager.getConnection(url+";create=true");
                
                conn.prepareStatement("create table THETABLE (I integer, S
varchar(100))").execute();
                conn.prepareStatement("create index THEINDEX_ON_I on
THETABLE (I)").execute();
                conn.prepareStatement("create index THEINDEX_ON_S on
THETABLE (S)").execute();
                for(int i=0; i<42; ++i) { 
                        PreparedStatement stmt =
conn.prepareStatement("insert into THETABLE values (?, ?)");
                        stmt.setInt(1, i);
                        stmt.setString(2, ""+i);
                        stmt.execute();
                }
                
                ResultSet rset = conn.getMetaData().getIndexInfo(null, null,
"THETABLE", false, false);
                while(rset.next()) {
                        String[] columns = new String[]{"TABLE_NAME",
"INDEX_NAME", "TYPE", "CARDINALITY"};
                        for(int i=0; i<columns.length; ++i) {
                                System.out.println(columns[i]+" =
'"+rset.getString(columns[i])+"'");
                        }
                        
                        if(rset.getShort("TYPE") ==
DatabaseMetaData.tableIndexStatistic) {
                                System.out.println("--- Success ---");
                        }
                        System.out.println("---");
                }
        }
}

When I run this program, I get the following output:

TABLE_NAME = 'THETABLE'
INDEX_NAME = 'THEINDEX_ON_I'
TYPE = '3'
CARDINALITY = 'null'
---
TABLE_NAME = 'THETABLE'
INDEX_NAME = 'THEINDEX_ON_S'
TYPE = '3'
CARDINALITY = 'null'
---

Note that a TYPE of 3 is DatabaseMetaData.tableIndexOther, which is not
useful to me for my row-counting purposes.  (I need tableIndexStatistic
(0).)

Also note that "--- Success ---" is NOT printed.  When I run this same code
a Microsoft SQL Server database, though, it is printed.

I realize that the JDBC docs don't say that a row with TYPE equal to
tableIndexStatistic is /required/ to be returned by getIndexInfo().  But I
am wondering if anyone can help me out by commenting on any of this.  In
particular:

- why Derby's DatabaseMetaData.getIndexInfo() doesn't return a TYPE ==
tableIndexStatistic row 
- how Derby might be made to return one, if possible 
- any alternate way of achieving my goal of a fast row count 

Thanks in advance.


Reply via email to