QueryDSL not using Postgres Indexes
我在Spring应用程序上使用Hibernate和QueryDSL以及PostgreSQL,并且在我的过滤列表中遇到了一些性能问题。 使用StringPath类,我调用startsWithIgnoreCase,endsWithIgnoreCase或containsIgnoreCase。
生成的查询似乎具有以下where子句:
1 | WHERE lower(person.firstname) LIKE ? ESCAPE '!' |
使用较低的查询不会利用Postgres索引。 在开发人员数据库中,使用ILIKE关键字查询最多需要1秒而不是10毫秒。
有没有办法使用Postgres的ILIKE获得谓词,因为Ops似乎没有提供它?
谢谢
不得不更新这个:
我们找到了一种通过在我们的自定义Hibernate方言中使用ilike注册SQL函数来创建所需的Postgres运算符的方法。
ilike示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | //Postgres Constants Operators public class PostgresOperators { private static final String NS = PostgresOperators.class.getName(); public static final Operator<Boolean> ILIKE = new OperatorImpl<>(NS,"ILIKE"); } //Custom JPQLTemplates public class PostgresTemplates extends HQLTemplates { public static final PostgresTemplates DEFAULT = new PostgresTemplates(); public PostgresTemplates() { super(); add(PostgresOperators.ILIKE,"my_ilike({0},{1})"); } } |
使用jpaquery时指定JPQLTemplates
1 | new JPAQuery(entityManager, PostgresTemplates.DEFAULT); |
现在它变得棘手,我们无法直接使用ilike,已经注册了"ilike"关键字的问题,所以我们制作了一个ilike函数并将其注册到一个定制的春天休眠方言。
我们的application.yml指定:
1 2 | #SEE JPA http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html spring.data.jpa:com.example.customDialect.config.database.ExtendedPostgresDialect |
然后
1 2 3 4 5 6 | public class ExtendedPostgresDialect extends org.hibernate.dialect.PostgreSQL82Dialect { public ExtendedPostgresDialect() { super(); registerFunction("my_ilike", new PostgreSQLIlikeFunction()); } } |
我们尝试使用registerKeyword("ilike"),没有用,我们继续使用我们的函数和以下实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | public class PostgreSQLIlikeFunction implements SQLFunction { @Override public Type getReturnType(Type columnType, Mapping mapping) throws QueryException { return new BooleanType(); } @SuppressWarnings("unchecked") @Override public String render(Type firstArgumentType, List args, SessionFactoryImplementor factory) throws QueryException { if (args.size() != 2) { throw new IllegalArgumentException( "The function must be passed 2 arguments"); } String str1 = (String) args.get(0); String str2 = (String) args.get(1); return str1 +" ilike" + str2; } @Override public boolean hasArguments() { return true; } @Override public boolean hasParenthesesIfNoArguments() { return false; } } |
这就是它,现在我们可以通过以下方式使用ILIKE:
1 | BooleanOperation.create(PostgresOperators.ILIKE, expression1, expression2).isTrue() |
我有完全相同的问题 -
引入具有
1 2 3 4 5 6 | public class ExtendedPostgresDialect extends org.hibernate.dialect.PostgreSQL9Dialect { public ExtendedPostgresDialect() { super(); registerFunction("my_ilike", new SQLFunctionTemplate(BooleanType.INSTANCE,"(?1 ilike ?2)")); } } |
指定Hibernate使用的这个方言(我使用Java配置):
1 2 3 | Properties props = new Properties(); props.setProperty("hibernate.dialect","com.example.ExtendedPostgresDialect"); factory.setJpaProperties(props); |
就是这样,现在你可以使用它:
1 | BooleanTemplate.create("function('my_ilike', {0}, {%1%})", stringPath, value).isTrue(); |