为什么 Jpa 查询绑定参数比带有 like 子句的原始参数慢得多?

Why Jpa query bound parameters are dramatically slower than raw parameters with like clause?

当我通过外部设置参数执行查询时,查询执行时间变得非常慢。

StopWatch stopWatch = new StopWatch();
stopWatch.start();
Query nativeQuery = mEntityManager.createNativeQuery(
    "select first 100 * from ALL$ACC allacc0_ where allacc0_.code like ? order by allacc0_.code asc");
nativeQuery.setParameter(1, "FIMA%");
List resultList = nativeQuery.getResultList();
stopWatch.stop();
System.out.println(stopWatch.prettyPrint() + " Total row count: " + resultList.size());

秒表'':运行时间(毫秒)=30868总行数:4

stopWatch = new StopWatch();
stopWatch.start();
Query nativeQuery1 = mEntityManager.createNativeQuery(
    "select first 100 * from ALL$ACC allacc0_ where allacc0_.code like 'FIMA%' order by allacc0_.code asc");
List resultList1 = nativeQuery1.getResultList();
stopWatch.stop();
System.out.println(stopWatch.prettyPrint()+ " Total row count: " + resultList1.size());

StopWatch '': 运行 时间(毫秒)= 10 总行数:4

你知道为什么吗?

spring-data-jpa 2.1.3.RELEASE
jaybird.version3.0.5

问题是当使用绑定变量时 Firebird 无法优化 LIKE 因为它不知道你要使用什么值,所以它必须假设最坏的情况并创建一个计划不能为该字段使用索引。

另一方面,当您使用仅以 %-通配符结尾的文字(并且在其他地方不包含通配符 _%)时,Firebird 可以优化使用索引。例如,当您使用 allacc0_.code like 'FIMA%' 时,Firebird 将像您使用 allacc0_.code starting with 'FIMA' 一样执行您的查询,并且 starting with 可以使用索引(如果可用)。

如果您希望参数具有相同的行为,请改写您的查询以使用 starting with

Query nativeQuery = mEntityManager.createNativeQuery("select first 100 * from ALL$ACC allacc0_ where allacc0_.code starting with ? order by allacc0_.code asc");
nativeQuery.setParameter(1, "FIMA");

LIKE 的 Firebird 语言参考中也对此进行了记录:

About LIKE and the Optimizer

[..] the LIKE predicate does not use an index. However, if the predicate takes the form of LIKE 'string%' , it will be converted to the STARTING WITH predicate, which will use an index.

So—if you need to search for the beginning of a string, it is recommended to use the STARTING WITH predicate instead of the LIKE predicate.

您应该在数据库级别启用强制参数支持

MS SQL 参数化 = FORCED

Oracle CURSOR_SHARING = 强制