【问题标题】:Spring Data Repository - Paging large data sets (EclipseLink)Spring Data Repository - 分页大型数据集 (EclipseLink)
【发布时间】:2015-10-28 16:59:40
【问题描述】:

我正在使用 Spring Data 和 EclipseLink JPA 对数据库结果集进行服务器端分页。我一切正常,我得到了预期的分页结果,但我注意到大型数据集(数百万行)的性能受到影响。返回一个包含 20 个结果的页面大约需要 5 分钟。也许这是意料之中的,但我关心的是查询输出。

我的日志输出:

SELECT COUNT(filename) FROM document
SELECT filename, datecaptured, din, docdate, docid, doctype, drawer, foldernumber, format, pagenumber, tempfilename, userid FROM document ORDER BY din ASC

我知道为了分页,Spring 需要知道最大行数,所以第一个查询是有意义的。

第二个查询是拉取整个数据库,当时我专门只要求 20 个偏移量为 0 的结果(页面)。


Spring/EclipseLink/JPA 实际上是抓取整个数据集然后只返回子集分页请求吗?

如果是这样,我应该如何修改我的存储库类以提高效率?

我的测试用例:

@Test
public void getPagedDocumentsTest() throws IOException {
    Page<Document> requestedPage = documentRepository.findAll(new PageRequest(0, 20, Sort.Direction.ASC, "din"));

    Assert.assertNotNull("Page is null", requestedPage);
    Assert.assertNotNull("Page is empty", requestedPage.getContent());

    List<Document> documents = requestedPage.getContent();

    LOG.info("{}", documents);
    LOG.info("{}", documents.size());
}

我的存储库类:

import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;

import com.example.data.model.Document;

@Repository
public interface DocumentRepository extends PagingAndSortingRepository<Document, String> {

}

编辑 - 根据@Chris 的建议

尝试将平台添加到我的属性中,但没有任何影响:

eclipselink.weaving=static
eclipselink.allow-zero-id=true
eclipselink.target-database=SQLServer
eclipselink.logging.level=FINE

还尝试将其添加到我的配置中(我正在使用 Java Config):

@Bean
public LocalContainerEntityManagerFactoryBean entityManager() {
    LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
    factory.setPersistenceUnitName("ExampleUnit");
    factory.setPackagesToScan("com.example.data.model");

    EclipseLinkJpaVendorAdapter eclipseLinkVendorAdapter = new EclipseLinkJpaVendorAdapter();
    eclipseLinkVendorAdapter.setDatabase(Database.SQL_SERVER);
    eclipseLinkVendorAdapter.setDatabasePlatform("SQLServer");
    factory.setJpaVendorAdapter(eclipseLinkVendorAdapter);

    factory.setDataSource(dataSource());
    factory.setJpaProperties(jpaProperties());
    factory.setLoadTimeWeaver(new InstrumentationLoadTimeWeaver());

    return factory;
}

看起来平台设置正确。

[EL Config]: connection: 2015-08-06 12:04:05.691--ServerSession(686533955)--Connection(1896042043)--Thread(Thread[main,5,main])--connecting(DatabaseLogin(
    platform=>SQLServerPlatform
    user name=> ""
    connector=>JNDIConnector datasource name=>null
))

但两者都没有帮助。 SQL 查询输出也保持不变。

编辑

找到了一个相关问题,@Chris 给出了类似的答案:

EclipseLink generated SQL doesn't include pagination

【问题讨论】:

  • 尝试指定目标数据库平台 EclipseLink 将在持久性属性中使用,以确保如果设置了最大和第一个结果,它将使用数据库过滤(SQL 中内置的限制/行数)而不是比 JDBC 过滤。
  • 感谢@Chris 的建议,但添加平台并不能解决问题;查看我的编辑。
  • 您应该在din 上创建一个索引。这样(排序的)索引将用于查找页面对应的数据库行,而不是先进行全表扫描,然后再进行排序。
  • 我添加了索引,但没有解决问题;执行时间保持在 5 分钟左右。

标签: spring jpa pagination eclipselink spring-data


【解决方案1】:

您应该考虑的一件事是您是否真的需要知道页数/元素总数。如果您要从包含数百万个元素的结果集中返回一个页面,那么您的用户很可能对浏览所有这些页面都不感兴趣:)。也许您的前端以无限滚动的形式显示数据,只需要知道是否还有页面,而不是页面数。

如果其中任何一种情况适用于您,您应该考虑返回 Slice 而不是 Page,如下所示:

public Slice<MyClass> findByMyField(..);

这样一来,Spring Data 不再需要昂贵的Count,而是只要求比您最初想要的多一个元素。如果该元素存在,Slice 将从 hasNext 方法返回 true。

在我工作的地方,我们最近将 Slices 用于几个大型数据集并使用正确的索引(在 clearing the database cache 之后:)我们已经看到了一些非常显着的收益。

【讨论】:

  • 很好的建议@Apokralipsa。我确实注意到使用 Slice 可以显着提高性能。正如您所提到的,count 花费了相当多的时间。如果我不必对结果进行分页,我一定会记住这一点。
  • 您可以使用 Slices 对结果进行分页。您可以像使用 Page 一样声明 Pageable 参数。你只是不知道提前有多少页面。
【解决方案2】:

我检查过的 EclipseLink 2.5 源代码支持内置在以下数据库平台类中的数据库级过滤:

  • DB2 平台
  • 德比平台
  • 火鸟平台
  • H2平台
  • HANAP平台
  • HSQL 平台
  • MySQL 平台
  • Oracle 平台
  • PostgreSQL 平台
  • Symfoware 平台

其中的每一个都会覆盖 printSQLSelectStatement 方法,以利用它们各自的数据库功能来允许在 SQL 本身中进行过滤。其他平台将需要使用 JDBC 过滤,这取决于驱动程序来限制行 - 它们可能能够优化查询,但它是特定于驱动程序的,我相信这就是为什么您的查询需要比您想要的更长的时间。

我不太了解 SQLServer,无法说明它有哪些可以在 SQL 中使用的等效功能,但是如果你找到它,你需要创建一个 SQLServerPlatform 子类,重写 printSQLSelectStatement 方法,就像在上面的类,然后指定要使用的平台类。还请提交错误/功能以将其包含在 EclipseLink 中。

此处描述了其他选项: http://wiki.eclipse.org/EclipseLink/Examples/JPA/Pagination

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多