我在Spring应用程序上使用Hibernate和QueryDSL以及PostgreSQL,并且在我的过滤列表中遇到了一些性能问题。使用StringPath类,我调用了startsWithIgnoreCase,endsWithIgnoreCase或containsIgnoreCase。 生成的查询似乎具有以下where子句:
WHERE lower(person.firstname) LIKE ? ESCAPE '!'
使用较低版本,查询没有利用Postgres索引。在开发人员数据库中,使用ILIKE关键字查询最多需要1秒而不是10毫秒。
有没有办法使用Postgres获得谓词' ILIKE,正如Ops似乎没有提供它?
由于
答案 0 :(得分:2)
不得不更新:
通过在我们的自定义Hibernate方言中使用ilike注册SQL函数,我们找到了一种创建所需Postgres运算符的方法。
ilike的例子:
//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
new JPAQuery(entityManager, PostgresTemplates.DEFAULT);
现在它变得棘手,我们无法直接使用ilike,已经注册了“ilike”关键字的问题,所以我们制作了一个ilike函数并将其注册到一个自定义的Spring hibernate Dialect。
我们的application.yml指定:
#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
然后
public class ExtendedPostgresDialect extends org.hibernate.dialect.PostgreSQL82Dialect {
public ExtendedPostgresDialect() {
super();
registerFunction("my_ilike", new PostgreSQLIlikeFunction());
}
}
我们尝试使用registerKeyword(“ilike”),没有用,我们继续使用我们的函数和以下实现。
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:
BooleanOperation.create(PostgresOperators.ILIKE, expression1, expression2).isTrue()
答案 1 :(得分:1)
我遇到了完全相同的问题 - lower(column)
导致错误的pg统计信息计算并且计划请求效率不高,ilike
解决了问题。我还没有理解OP的答案中哪些部分与解决方案有关,所以重新采用相同的方法,但稍微缩短一点。
介绍具有my_ilike
功能的新方言及其实施:
public class ExtendedPostgresDialect extends org.hibernate.dialect.PostgreSQL9Dialect {
public ExtendedPostgresDialect() {
super();
registerFunction("my_ilike", new SQLFunctionTemplate(BooleanType.INSTANCE, "(?1 ilike ?2)"));
}
}
指定Hibernate使用的这个方言(我使用Java配置):
Properties props = new Properties();
props.setProperty("hibernate.dialect", "com.example.ExtendedPostgresDialect");
factory.setJpaProperties(props);
那就是它,现在你可以使用它了:
BooleanTemplate.create("function('my_ilike', {0}, {%1%})", stringPath, value).isTrue();