如何优化查询记录数的SQL操作?

我有一个函数用于取给定表名的表记录数,如下:



/**
* 取给定表的记录数。
*
* @param tableName 表名
* @return 该表中的记录总数
*/
public static int getRecoundCount(final String tableName){
//空值捕获
if(StringUtil.isNullorBlank(tableName))return 0;
//记录数
int count = 0;
DBOperator dbo = null;
try{
dbo = new DBOperator();
//TODO: preparestatement...... 优化!!!!!!!!!
final String sql =
"SELECT COUNT(*) FROM " + tableName;
dbo.setPrepareStatement(sql);
//dbo.setString(1,tableName);
final ResultSet rs = dbo.executeQuery();
//rs.last();
//count = rs.getRow();
//取记录数
if(rs.next()){
count = rs.getInt(1);
}
rs.close();
}catch(Exception ex){
ex.printStackTrace();
log.error(ex.getMessage());
}finally{
dbo.close();
dbo = null;
}
return count;
}
//end getRecordCount()


但我测试的数据显示该方法效率很低,目前数据库数据很少,平均在850ms左右,数据库是MYSQL的,好像用count(*)效率不高,但我试过取ID值,然后rs.last();rs.getRow()等,但效率相差无几,而且因为是通用函数,故不可能指定ID名(数据库中主键名都不相同的)

所以想问问高手有什么可以优化的或其他更号效率的方法?
谢谢先:)


另:我本来用preparestatement,但在:
SELECT COUNT(*) FROM (?)时出问题,无法set进这个表名,说sql语法错:(不知道怎么回事:(

I don't know there is a better way than get count(*) in general.
Maybe you should look at how to cluster the table for better performance, but it varies on database, for mysql, I don't know the option.

I have use getCount(*) in mysql on a table with over 300,000 records, most of time it returns within a couple of seconds. that table reside on INNODB, if you using ISAM, it should even faster, as base on mysql doc, when count(*) with where, it use MyISAM table instead of full table scan.

You can do prepared statement that way, only the param for where can be bind, plus I don't think you have any gain here as with where clause or join, execution plan is very easy to prepared.

你的这个操作要做到数据库无关性吗?
如果只限制于mysql的话, 你可以用execute
SHOW TABLE STATUS

得到的ResultSet里面的name和rows就是你要的.

如果是要求数据库无关性的话, 可能有2点会对性能有帮助:
1. 先使用ResultSet.last(), 然后用ResultSet.getRow()得到总数, 不同的jdbc driver实现上述的方法不一样, 性能会有很大的差别.

2. 建立statment的时候加上
ResultSet.TYPE_SCROLL_INSENSITIVE
ResultSet.CONCUR_READ_ONLY等优化常数
只读的ResultSet的性能会比其他要好很多.

又想到一点:
你可以使用table的meta data得到它的primarykey field的名字, 然后建立一个table name和pk field name的mapping cache, 这样就可以不用count(*)了.

thanks

确实想做到数据库无关,因为有几个功能恨常用,所以想提出来,现在放在一个Sequence类里,比如nextID(final String tableName);getMaxID(final String tableName);getRecordCount(final String tableName)什么的,都使用标准的SQL来做,不过这样放弃了很多数据库的特性,考虑用抽象类,然后具体实现由子类来做,这样就可以使用不同数据库的特性了,而且扩展也容易,构思中,高手给点意见:)谢谢先:)

If you don't worry about deleting record, a seperate sequence number will help.

If you don't worry other app alter DB directly that can bypass your db access layer, then your can maitain count thru second table/object/

Abstract method make sense, as almost every DB provide a way to avoid table scanning, some thru their system table, e.g in mssql, it's stored in sysindex.

Cheers

Will
SELECT COUNT(1) FROM ...

be faster ?

To jpenguin,
可以说一下count(1)的意思吗? 是标准的sql语法吗? 我在sql手册里面没有找到, 不过在mysql 和msssql上测试了一下, 很好用.

我测试过oracle
select count(1) from table
性能差不多,没有明显的提高速度。

我在Oracle中试过也可以。

我在MSSQL中找到的帮助,如下:
语法
COUNT ( { [ ALL | DISTINCT ] expression ] | * } )

参数
ALL

对所有的值进行聚合函数运算。ALL 是默认设置。

DISTINCT

指定 COUNT 返回唯一非空值的数量。

expression

一个表达式,其类型是除 uniqueidentifier、text、image 或 ntext 之外的任何类型。不允许使用聚合函数和子查询。

当然可以用了,你想想在数据库里算加法怎么算:select 1+1 from dual;
答案是2,因为dual是虚表,所以只有一行纪录,如果是select 1+1 from tab;就会有若干条返回值2,就是这样,所以无论你在哪一个帮助文件里找都不会有的。记住关系形数据库的一点原则:数据仅以表的形式提供给用户!

因为有几个功能恨常用,所以想提出来,现在放在一个Sequence类里,比如nextID(final String tableName);getMaxID(final String tableName);getRecordCount(final String tableName)什么的

这些功能提出来不一定能满足全部要求吧,比如要从几个表里查询一些记录出来,或者从一个表里有条件的查一些记录,用getRecordCount()怎么实现呢,还得抽象另一个方法出来?