QueryDSL 不使用 Postgres 索引
QueryDSL not using Postgres Indexes
我在 Spring 应用程序上使用 Hibernate 和 QueryDSL 以及 PostgreSQL,我的筛选列表面临一些性能问题。使用 StringPath class,我正在调用 startsWithIgnoreCase、endsWithIgnoreCase 或 containsIgnoreCase。
生成的查询似乎具有以下 where 子句:
WHERE lower(person.firstname) LIKE ? ESCAPE '!'
使用较低的查询没有利用 Postgres 索引。在开发数据库上,使用 ILIKE 关键字查询最多需要 1 秒而不是 10 毫秒。
有没有办法使用 Postgres 的 ILIKE 获得谓词,因为 Ops 似乎没有提供它?
谢谢
不得不更新这个:
我们找到了一种创建所需 Postgres 运算符的方法,方法是在我们自定义的 Hibernate 方言中使用 ilike 注册一个 SQL 函数。
喜欢的例子:
//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休眠方言。
我们的 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()
我遇到了完全相同的问题 - 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();
我在 Spring 应用程序上使用 Hibernate 和 QueryDSL 以及 PostgreSQL,我的筛选列表面临一些性能问题。使用 StringPath class,我正在调用 startsWithIgnoreCase、endsWithIgnoreCase 或 containsIgnoreCase。 生成的查询似乎具有以下 where 子句:
WHERE lower(person.firstname) LIKE ? ESCAPE '!'
使用较低的查询没有利用 Postgres 索引。在开发数据库上,使用 ILIKE 关键字查询最多需要 1 秒而不是 10 毫秒。
有没有办法使用 Postgres 的 ILIKE 获得谓词,因为 Ops 似乎没有提供它?
谢谢
不得不更新这个:
我们找到了一种创建所需 Postgres 运算符的方法,方法是在我们自定义的 Hibernate 方言中使用 ilike 注册一个 SQL 函数。
喜欢的例子:
//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休眠方言。
我们的 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()
我遇到了完全相同的问题 - 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();