我确信我可以提高hibernate的以下findByName查询的性能:
public List<User> findByName(String name) {
session.createCriteria(User.class).add(Restrictions.eq("name", name)).list();
}
瓶颈是findByName方法而我不能使用id。
在我的情况下,我知道名称是唯一的,但在name属性中添加索引注释并没有提高性能。我做了以下事情:
class User {
@Index(name = "nameIdx")
private String name;
}
我应该以哪种方式改进它,或者更重要的是:我应该首先以哪种方式改进它?我将需要包含所有集合(layz与否)的完整对象以及此类的deps。
或者我可以改进它,如果我想要几个User对象(并且知道几个名字)?
UPDATE1:
@Index注释没有提高性能,因为数据库已经有了索引,因为我的唯一约束注释:
@UniqueConstraint(columnNames = {"name"})
UPDATE2:
仔细阅读答案!
在SQL日志记录的帮助下,我发现真正的问题是虽然我没有提交或刷新事务,但是引发了很多更新和插入语句。 这背后的原因是我做了(循环):
User u = findByName(name);
if(u == null)
attach(u = new User(name));
所以hibernate需要在每次findByName查询之前将新创建的用户刷新到db。我用自己的缓存解决方法(LinkedHashMap)解决了这个问题。
我通过Jens Schauder的提示做了另一项改进:
public Collection<User> findByNames(Collection<String> names) {
return session.createCriteria(User.class).
add(Restrictions.in("name", names)).list();
}
将某些用户集合指定为非懒惰时,可以进一步改进:
@LazyCollection(LazyCollectionOption.FALSE)
Read this answer以获得更好的选择。
对我来说,最后也是最重要的一个是:用list替换我的SortedSet项,并在getItems方法中执行以下操作:
Set set = new LinkedHashSet(items);
items.clear();
items.addAll(set);
Collections.sort(items, itemComparator);
return Collections.unmodifiableCollection(items);
因此,hibernate可以处理项目集合(即添加),而无需从数据库加载整个集合。
@Pascal Thivent和@Jens Schauder :一堆谢谢!对不起,我只能接受一个答案: - /
有用的记录设置:
log4j.logger.org.hibernate.tool.hbm2ddl=INFO, StdoutApp
log4j.logger.org.hibernate.SQL=INFO, StdoutApp
# additionally provide the information which parameters will be bound:
log4j.logger.org.hibernate.type=TRACE
答案 0 :(得分:3)
您没有提供足够的信息来获得完整的答案,但这里有一些想法:
正如您所看到的,您有很多调整选项。唯一一个我期望对这项努力产生良好影响的是考虑一个指数。当然,当我们有关于问题的更多信息时,这可能会改变(例如完整的表结构,索引,hibernate映射,表的大小......)
根据评论更新:
调整时,第一个问题是:我们需要调整什么? 它是将Criteria转换为SQL语句吗?如果是这样,直接提供sql语句就可以完成这项工作。
是sql语句的实际执行吗?如果是这样,确定发布代码产生的sql语句将是第一件事。
我从未见过存储过程使事情变得更快的真实案例。当然,这并不意味着这种情况不存在。但现代rdbms的优化器非常聪明。
因此,为了正确启动:设置日志记录,以便您看到每个带有精确时间戳的sql语句。以及您正在调整的完整过程的开始和结束时间。如果这是大约数百次执行,你将不得不重新设置。
这将告诉您是否执行了sql语句,并且占用了大量时间,如果它是一个导致问题的sql语句。
大多数时候sql语句都表现不好,但不应该妄下结论。
更新许多名称部分:
您可以使用InExpression:http://docs.jboss.org/hibernate/core/3.3/api/org/hibernate/criterion/InExpression.html一次查找多个对象。这比单个查询更快。
答案 1 :(得分:2)
在我的情况下,我知道名称是唯一的,但在name属性中添加索引注释并没有提高性能。瓶颈是
findByName
方法。
我不会相信这......直到你展示一些证明我错了的数字:)所以:
SELECT * FROM USER u WHERE u.NAME = 'foo'
)和执行时间。稍后,您可以考虑激活二级缓存并缓存查询。但数据库是开始的地方(过早缓存事物只会隐藏真正的问题)。
衡量一切! 如果你无法衡量它,你无法改善它。 - Lord Kelvin 。