Spring数据存储库-分页大型数据集(EclipseLink)
我使用Spring数据和EclipseLink JPA对数据库结果集进行服务器端分页。我的一切都正常工作,我得到了预期的分页结果,但我注意到在大数据集(数百万行)上性能下降。返回包含20个结果的页面大约需要5分钟。也许这是意料之中的,但我关心的是查询输出 我的日志输出:Spring数据存储库-分页大型数据集(EclipseLink),spring,jpa,pagination,eclipselink,spring-data,Spring,Jpa,Pagination,Eclipselink,Spring Data,我使用Spring数据和EclipseLink JPA对数据库结果集进行服务器端分页。我的一切都正常工作,我得到了预期的分页结果,但我注意到在大数据集(数百万行)上性能下降。返回包含20个结果的页面大约需要5分钟。也许这是意料之中的,但我关心的是查询输出 我的日志输出: SELECT COUNT(filename) FROM document SELECT filename, datecaptured, din, docdate, docid, doctype, drawer, foldernu
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());
}
还尝试将其添加到我的配置中(我正在使用Java配置):
看起来平台设置正确
[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的答案类似的相关问题:
< P>你应该考虑的是你是否真的需要知道元素的页数/总数。如果您从一个包含数百万个元素的结果集中返回一个页面,那么您的用户很可能对浏览所有这些页面都不感兴趣:)。也许你的前端会在一个无限长的卷轴中显示数据,只需要知道是否还有更多的页面,而不是页面数
如果有任何情况适用于您,您应该考虑返回<代码>切片>代码>而不是<代码>页面<代码>,如:
public Slice<MyClass> findByMyField(..);
public Slice findByMyField(..);
这样,Spring数据就不会进行昂贵的计数
,只会要求比您最初想要的多出一个元素。如果该元素存在,则切片将从hasNext
方法返回true
我在工作中,我们最近使用了几个大数据集的切片和正确的索引(以及之后):我们已经看到了一些非常显著的收益。
< P>你应该考虑的是你是否需要知道元素的页数/总数。如果您从一个包含数百万个元素的结果集中返回一个页面,那么您的用户很可能对浏览所有这些页面都不感兴趣:)。也许你的前端会在一个无限长的卷轴中显示数据,只需要知道是否还有更多的页面,而不是页面数
如果有任何情况适用于您,您应该考虑返回<代码>切片>代码>而不是<代码>页面<代码>,如:
public Slice<MyClass> findByMyField(..);
public Slice findByMyField(..);
这样,Spring数据就不会进行昂贵的计数
,只会要求比您最初想要的多出一个元素。如果该元素存在,则切片将从hasNext
方法返回true
在我工作的地方,我们最近对几个大型数据集使用了切片,并使用了正确的索引(以及之后的:),我们看到了一些非常显著的收益。EclipseLink 2.5源代码,我检查过它,我相信它支持以下数据库平台类中内置的数据库级过滤:
- DB2Platform
- 德比平台
- 火鸟平台
- H2平台
- 汉娜平台
- HSQL平台
- MySQLPlatform
- OraclePlatform
- PostgreSQLPlatform
- SymfowarePlatform
其中每一个都重写printSQLSelectStatement方法,以利用各自的数据库功能,允许在SQL本身中进行筛选。其他平台将需要使用JDBC过滤,这依赖于驱动程序来限制行-它们可能能够优化查询,但它是特定于驱动程序的,我相信这就是为什么查询比您希望的时间更长
我对SQLServer的了解还不够透彻,无法说出它具有哪些可以在SQL中使用的等效功能,但如果找到了,则需要创建一个SQLServerPlatform子类,像在上述类中那样重写printSQLSelectStatement方法,然后指定使用该平台类。还请提交一个bug/特性,以便将其包含在EclipseLink中
此处介绍了其他选项:
我查看的EclipseLink 2.5源代码我相信它支持以下数据库平台类中内置的数据库级过滤:
- DB2Platform
- 德比平台
- 火鸟平台
- H2平台
- 汉娜平台
- HSQL平台
- MySQLPlatform
- OraclePlatform
- PostgreSQLPlatform
- SymfowarePlatform
其中每一个都重写printSQLSelectStatement方法,以利用各自的数据库功能,允许在SQL本身中进行筛选。其他平台将需要使用JDBC过滤,这依赖于驱动程序来限制行-它们可能能够优化查询,但它是特定于驱动程序的,我相信这就是为什么查询比您希望的时间更长
我对SQLServer的了解还不够透彻,无法说出它具有哪些可以在SQL中使用的等效功能,但如果找到了,则需要创建一个SQLServerPlatform子类,像在上述类中那样重写printSQLSelectStatement方法,然后指定使用该平台类。还请提交一个bug/特性,以便将其包含在EclipseLink中
此处介绍了其他选项:
尝试指定EclipseLink将在持久性属性中使用的目标数据库平台,以确保如果设置了max和first结果,它将使用数据库筛选(SQL中内置的limit/rownum)而不是JDBC筛选。而不是
[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
))
public Slice<MyClass> findByMyField(..);