【问题标题】:EclipseLink generated SQL doesn't include paginationEclipseLink 生成的 SQL 不包括分页
【发布时间】:2014-11-14 02:39:51
【问题描述】:

(我的环境:Windows 7 x64 和 Server 2008,EclipseLink 2.5.2,我已经使用 JTDS 和 MS JDBC 驱动程序以及 MS SQL Server Express 2008 和 2012 进行了以下尝试。)

我正在对包含 5 到 5000 万行的表进行分页查询,其中大约 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 吗?我看到了两种可能性:

  • 这是完整生成的 SQL,但 EclipseLink 正在执行其他操作来完成分页。
  • EclipseLink 在添加分页内容之前记录此生成的 SQL

【问题讨论】:

    标签: sql-server jpa pagination eclipselink offset


    【解决方案1】:

    尝试将 EclipseLink 中的日志级别设置为 Finest,并检查正在使用的数据库平台。 EclipseLink 日志记录还将显示发送到数据库的内容。这应该记录与您从 getSQLString() 获得的相同的 SQL,但允许您验证您正在执行正确的 api,并且初始启动日志将显示正在使用的平台是否与您的数据库匹配,否则将需要使用 target-database 属性指定:http://www.eclipse.org/eclipselink/documentation/2.4/jpa/extensions/p_target_database.htm

    如果平台支持,EclipseLink 将在生成的 SQL 中使用分页,如http://wiki.eclipse.org/EclipseLink/Examples/JPA/Pagination 所述,否则它使用 JDBC api 来限制发送的结果,然后跳转到返回结果集中的第一个结果,这如果分页完全在数据库中完成,效率会更低。

    【讨论】:

      【解决方案2】:

      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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-06
        • 2013-06-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-01-15
        相关资源
        最近更新 更多