我有一个实体有201个字段(testId,test1 ... test200),id是long类型,其他是String。我用HQL在Hibernate中搜索了它
this.getTestDao()。getHibernateTemplate()。find(“from test where testId< = 10000”)
线程转到 spring-hibernate3.jar 然后
//Method from spring-hibernate3.jar
//org.springframework.orm.hibernate3.HibernateTemplate
public List find(final String queryString, final Object values[])
throws DataAccessException
{
return (List)execute(new HibernateCallback() {
public Object doInHibernate(Session session)
throws HibernateException
{
Query queryObject = session.createQuery(queryString);
prepareQuery(queryObject);
if(values != null)
{
for(int i = 0; i < values.length; i++)
queryObject.setParameter(i, values[i]);
}
return queryObject.list();
}
}
, true);
}
但Java VisualVm(JDK中的一个监控软件)告诉我,方法 oracle.jdbc.driver.OracleStatement.getColumnIndex()为10,000个数据花费4404ms 我知道Hibernate很慢,但实际上是不可接受的,因为在sqldeveloper中使用相同的SQL只花费55ms。
我确信没有打印任何异常且每个fileld都是合法的。还有反编译代码 oracle.jdbc.driver.OracleStatement.getColumnIndex
//Method from oracle10.2 jdbc14.jar
// oracle.jdbc.driver.OracleStatement
int getColumnIndex(String s)
throws SQLException
{
if(!describedWithNames)
synchronized(connection)
{
synchronized(this)
{
connection.needLine();
doDescribe(true);
described = true;
describedWithNames = true;
}
}
for(int i = 0; i < numberOfDefinePositions; i++)
if(accessors[i].columnName.equalsIgnoreCase(s))
return i + 1;
DatabaseError.throwSqlException(6);
return 0;
}
来自显示器的图像 click to view
谢谢大家,感谢指出语法错误,如果存在的话。
答案 0 :(得分:0)
我遇到了同样的问题。我们使用 Hibernate 将一个非常“宽”的表(~200 列)加载到对象中。对于结果集中的每一行,Hibernate 将尝试“提取”每一列中的值使用其名称。为此,它调用“OracleStatement.getColumnIndex”方法(见上文)。这种愚蠢的方法通过遍历所有字段字段来查找索引...尝试查看列的名称是否与输入中的名称匹配。
所以如果有 200 列和 100 行。而“getColumnIndex”方法必须遍历列的一半(平均)才能找到它要查找的列,然后...
200 * 100 * 100 = 2,000,000 次字符串比较操作...
好像结果集中列的名称发生了变化!!!
但这是旧版 oracle 中的代码......准确地说是“ojdbj6.jar”(12.1.0.2.0)。所以我反编译了“ojdbc8.jar”(18.3.0.0.0)以查看是否有任何变化......它确实发生了。Oracle 的一些聪明人决定添加一个缓存:
int getColumnIndex(String paramString) throws SQLException {
ensureOpen();
Integer integer = (Integer)this.columnNameCache.get(paramString);
if (integer == null) {
integer = Integer.valueOf(getColumnIndexPrimitive(paramString));
if (this.columnNameCache.size() <= this.accessors.length)
this.columnNameCache.put(paramString, integer);
}
return integer.intValue();
}
所以@a_horse_with_no_name 说你的问题是 Oracle 驱动程序很旧时,它有点正确。
更新:
对于我的应用程序,我做了一个测试,将旧的 (11.2.0.3) 驱动程序与较新的 (18.3.0.0) 驱动程序的性能进行了比较。此测试执行一项操作,该操作对“宽”表执行 Hibernate 查询并滚动结果,同时将结果转换为 XML。使用新驱动程序,运行时间快了 4 倍。如果我可以从等式中消除 XML 逻辑,那么性能改进会更加显着。
底线:
如果您必须使用 Hibernate 对“宽”表或结果中有很多行的表进行查询,请确保使用最新的 JDBC 驱动程序。新驱动程序与旧数据库兼容。