(我的环境:Windows 7 x64和Server 2008,EclipseLink 2.5.2,我已尝试使用JTDS和MS JDBC驱动程序,以及MS SQL Server Express 2008和2012.)
我在一个表中进行分页查询,其中包含5-50万行,大约有500万行符合过滤条件。以下是我用于在UI中一次显示25行数据的分页查询。分页工作正常 - 列表每页只包含25行。但是,查询需要24秒才能返回25行,这看起来很长。
我的目标是记录生成的SQL,因此我可以确切地看到JPA如何在SQL Server 2008和2012中完成分页。但生成的SQL并不包含任何与分页有关的内容,这让我很奇怪我在生成的SQL中没有看到的其他内容。
查询:
CriteriaBuilder cb = JPA.em().getCriteriaBuilder();
CriteriaQuery<RGHICarrierPull> cq = cb.createQuery(RGHICarrierPull.class);
Root<RGHICarrierPull> from = cq.from(RGHICarrierPull.class);
CriteriaQuery<RGHICarrierPull> select = cq.select(from);
// Add filter/sort predicates to "predicates"
...
select.where(predicates);
// Apply pagination
records.setFirstResult((page-1)*limit);
records.setMaxResults(limit);
// Get data
List<RGHICarrierPull> lst = records.getResultList();
以编程方式记录生成的SQL:
// Log the sql for this query
Session session = JPA.em().unwrap(JpaEntityManager.class).getActiveSession();
DatabaseQuery databaseQuery = ((EJBQueryImpl)records).getDatabaseQuery();
databaseQuery.prepareCall(session, new DatabaseRecord());
System.out.println(databaseQuery.getSQLString());
记录的SQL:
SELECT t1.SHIPTO_ZIP, t1.WHSE, t1.ANYNBR1, t1.ANYTEXT1, t1.CREATE_DATE_TIME, t1.
MOD_DATE_TIME, t1.PULL_TIME, t1.PULL_TIME_AMPM, t1.PULL_TRLR_CODE, t1.USER_ID,
1.SHIP_VIA FROM Ship_Via t0, RGHI_Carrier_Pull t1 WHERE ((t1.WHSE = 'WHSE1') AND
(t0.SHIP_VIA = t1.SHIP_VIA)) ORDER BY t0.SHIP_VIA ASC, t1.SHIPTO_ZIP ASC
显然,这不是分页查询,因此如果我直接运行此查询,它会运行超过一分钟并返回所有500万行。如果我使用persistence.xml设置来记录所有JPA查询,并且如果我从MS SQL Server记录SQL,我会得到相同的结果。
这是实际生成的SQL吗?我看到两种可能性:
答案 0 :(得分:0)
尝试将EclipseLink中的日志级别设置为Finest,并检查正在使用的数据库平台。 EclipseLink日志记录还将显示发送到数据库的内容。这应该记录与从getSQLString()获得的SQL相同的SQL,但允许您验证您正在执行正确的api,并且初始启动日志记录将显示正在使用的平台是否与您的数据库匹配,否则它将需要使用target-database属性指定:http://www.eclipse.org/eclipselink/documentation/2.4/jpa/extensions/p_target_database.htm
如果plaform支持,EclipseLink将在生成的SQL中使用分页http://wiki.eclipse.org/EclipseLink/Examples/JPA/Pagination,否则它将使用JDBC api来限制发送的结果,然后跳转到返回结果集中的第一个结果如果分页完全在数据库中完成,则效率较低。
答案 1 :(得分:0)
EclipseLink(至少在当前版本2.6.1中)既不支持OFFSET-FETCH语法形式的SQL Server 2012分页,也不支持旧的SQL Server TOP语法,请查看EclipseLink Database Support。相反,EclipseLink在内部使用JDBC功能Statement.setMaxRows()
,它实质上丢弃了返回ResultSet
的过多行。到目前为止,还没有计划在未来的版本中支持这一点。
您可以尝试手动扩展SQLServerPlatform
和重写方法printSQLSelectStatement()
,类似于PostgreSQLPlatform.printSQLSelectStatement()
中的方式。工作原型在这里:https://github.com/roman-sinyakov/eclipselink/blob/master/SQLServer2012Platform.java。