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