为什么 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 = 强制
当我通过外部设置参数执行查询时,查询执行时间变得非常慢。
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 ofLIKE 'string%'
, it will be converted to theSTARTING 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 theLIKE
predicate.
您应该在数据库级别启用强制参数支持
MS SQL 参数化 = FORCED
Oracle CURSOR_SHARING = 强制