Почему параметры привязки запроса Jpa значительно медленнее, чем необработанные параметры с предложением like? - PullRequest
0 голосов
/ 12 декабря 2018

Когда я выполняю запрос, устанавливая параметр извне, время выполнения запроса резко замедляется.

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

1 Ответ

0 голосов
/ 13 декабря 2018

Проблема в том, что Firebird не может оптимизировать LIKE, когда используется переменная связывания, потому что он не знает, какое значение вы собираетесь использовать, поэтому он должен принять наихудший случай и создать план, который не может использовать индексдля поля.

С другой стороны, когда вы используете литерал, который заканчивается только % -wildcard (и не содержит подстановочных знаков _ или % в других местах), 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");

Это также задокументировано в справочнике по языку Firebird для LIKE:

О LIKE и оптимизаторе

[..] предикат LIKE не использует индекс.Однако, если предикат принимает форму LIKE 'string%', он будет преобразован в предикат STARTING WITH, который будет использовать индекс.

Так что, если вам нужно найти начало строки,рекомендуется использовать предикат STARTING WITH вместо предиката LIKE.

...