Java 用于只读的DataNumCache

Java 用于只读的DataNumCache,java,jdo,datanucleus,Java,Jdo,Datanucleus,我一直在尝试分析JDO查询的性能(我在mysql中使用内置dbcp) 我注意到,虽然我的查询可能非常快,但如果返回大量记录,query.execute()可能会慢得多(一个5ms的db查询可能需要40ms的执行时间) 我已经缩小了L1Cache的可能原因: 2015-04-17 21:03:46.325[work-3]调试DataNucleus.Cache-在一级缓存中找不到id为758“的对象[Cache size=153] 2015-04-17 21:03:46.325[work-3]调试D

我一直在尝试分析JDO查询的性能(我在mysql中使用内置dbcp)

我注意到,虽然我的查询可能非常快,但如果返回大量记录,query.execute()可能会慢得多(一个5ms的db查询可能需要40ms的执行时间)

我已经缩小了L1Cache的可能原因:

2015-04-17 21:03:46.325[work-3]调试DataNucleus.Cache-在一级缓存中找不到id为758“的对象[Cache size=153]

2015-04-17 21:03:46.325[work-3]调试DataNucleus.Cache-将对象“@442b0b9e”(id=“:758”)添加到一级缓存(loadedFlags=“[NYNNN]”)

2015-04-17 21:03:46.325[work-3]调试DataNucleus.Cache-在一级缓存中找不到id为759“的对象[Cache size=154]

2015-04-17 21:03:46.325[work-3]调试DataNucleus.Cache-对象“@3f978ede”(id=“:759”)添加到一级缓存(loadedFlags=“[NYNNNNN]”)

2015-04-17 21:03:46.326[work-3]调试DataNucleus.Cache-在一级缓存中找不到id为760“的对象[Cache size=155]

2015-04-17 21:03:46.326[work-3]调试DataNucleus.Cache-对象“@2e0f44f5”(id=“:760”)添加到一级缓存(loadedFlags=“[NYNNNNN]”)

2015-04-17 21:03:46.326[work-3]调试DataNucleus.Cache-在一级缓存中找不到id为“761”的对象[Cache size=156]

2015-04-17 21:03:46.326[work-3]调试DataNucleus.Cache-将对象“@7db2fe20”(id=“:761”)添加到一级缓存(loadedFlags=“[NYNNN]”)

这表明首先检查每个记录(查看它是否在缓存中,然后插入到缓存中)。由于有100或1000条记录,这项技术的性能似乎相当苛刻

此外,当PersistenceManager关闭时(我使用的是try with resources),这个缓存就会被销毁。( 因此,对于一个简单的select*from表:

  • 我们获得了记录
  • 我们改上课
  • 我们检查它是否已经在L1 cahce中(对于单次读取,它不会)
  • 我们插入到缓存中
  • 查询已完成
  • PersistenceManager已关闭
  • 缓存中的记录被清空(一次一条)
以下是一些示例代码:

        try (final PersistenceManagerProvider pmp = getReadPmp()) {
            Query q = pmp.get().newQuery(clazz, ":param1.contains(" + field + ")");
            @SuppressWarnings("unchecked") List<T> result = (List<T>) q.execute(values);
            return result;
        }
对于这样的查询,我只是在select中读取,缓存没有提供任何内容,因此它不应该影响我的性能。(顺便说一下,我尝试禁用一级缓存,这显然不是一个好主意)

以下是查询中的完整日志集:
这些都是调试日志(这可能会大大降低查询速度,但仍然支持这样一种理论,即从缓存中删除对象和插入对象的调用都是顺序的且耗时).

你不说时间花在哪里。查询通用编译?查询数据存储编译?执行?从ResultSet提取结果?事务提交(和对象生命周期更改)?一级缓存是一个映射,仅此而已,根据JDO(和JPA)只需分发一个具有特定对象id的对象规范。我看到没有缓存被清空记录“一次一条”…调用cache.clear(在地图上)时间花费在JDOQL performExecute上,但我将发布收集的完整日志,这样我们可以看到缓存被清除,并且每个记录的缓存被构造。我编辑以附加完整日志的要点,(我猜是因为销毁/添加是按顺序记录的(我可以看到日志之间的时间),它们是按顺序调用的。这可能是一个错误的假设。您可以在这里看到的另一件事是,实际查询和编译时间很快。日志中的大部分时间都花在一级缓存上。我看到日志消息,表示一个对象已从一级缓存中删除,但这并不意味着在下一个消息之前,所有时间都在一级缓存中e、 如前所述,从映射中删除对象很简单。为什么不看看他们的代码呢?
    @Override
    public void close() {
        if (tx != null && tx.isActive()) {
            final String stackTrace = new Throwable().getStackTrace()[1].toString(); // element 0 is this method
            LOGGER.error("ROLLING BACK UNCOMMITTED TRANSACTION FROM " + stackTrace);
            tx.rollback(); // never throws if isActive() is true
        }

        persistenceManager.close();
}