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

时间:2018-12-12 16:33:58

标签: hibernate spring-boot jpa firebird jaybird

当我通过在外部设置参数来执行查询时,查询执行时间会大大降低。

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());

StopWatch”:运行时间(毫秒)= 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.version 3.0.5

2 个答案:

答案 0 :(得分:1)

问题在于,当使用绑定变量时,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");

《 {@ 3}}的Firebird语言参考》中也对此进行了记录:

  

关于LIKE和优化程序

     

[..] LIKE谓词不使用索引。但是,如果   谓词采用LIKE 'string%'的形式,它将转换为   STARTING WITH谓词,它将使用索引。

     

因此-如果您需要搜索字符串的开头,则为   建议使用STARTING WITH谓词而不是LIKE   谓词。

答案 1 :(得分:0)

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

MS SQL参数化=强制

Oracle CURSOR_SHARING =强制