我正在开发应用程序,并且正在使用Spring Data JPA进行数据库操作。
我正在实现一种通过搜索栏查找朋友的功能。它的工作方式是,当您输入一些字符时,将在数据库中执行搜索以查找并显示10个与字符匹配的用户(名字以它开头,姓氏以它开头,并且还应该如果有人输入全名,则可以正常工作。
我已经编写了代码,它的工作方式如下:
@Query(nativeQuery = true,
value="SELECT * FROM users u WHERE (" +
"UPPER(first_name) like CONCAT(UPPER(:query),'%') OR " +
"UPPER(last_name) like CONCAT(UPPER(:query),'%') OR " +
"UPPER(CONCAT(first_name,' ', last_name)) like CONCAT(UPPER(:query),'%')" +
") LIMIT 10")
List<User> findByQueryLikeName(@Param("query") String query);
但是,当我查看此查询时,实际上似乎并不是最佳的性能选择。我对sql性能的了解并不多,但是我认为这是因为它结合了3个where语句和一个OR
运算符,并且还大量使用了一些函数,例如UPPER
和CONCAT
。我正在使用PostgreSQL。
能否请您评估一下这种查询在大量记录上是否表现良好?你能解释为什么/为什么不吗?您有任何改进技巧吗?
非常感谢!
答案 0 :(得分:1)
我会这样重写查询:
SELECT * FROM users u
WHERE concat(' ', u.first_name,' ', u.last_name) ILIKE ' ' || :query || '%';
您必须创建一个trigram索引来支持此操作:
CREATE EXTENSION pg_trgm;
CREATE INDEX ON users USING gin
(concat(' ', u.first_name,' ', u.last_name) gin_trgm_ops);
答案 1 :(得分:0)
正如注释中指出的那样,它可能太慢了,因为您正在WHERE子句中使用函数:
或者,您可以将另一个字段fullName
添加到您的实体,并在setFirstName()
和setLastName()
中进行更新,如下所示:
void setFirstName(String first){
this.fullName = first.toUpperCase() + " " + this.lastName.toUpperCase(); //TODO handle nulls
}
然后,您可以通过已经大写的fullName
进行查询,然后在Java中搜索大写字符串并进行简单的查询:
public List<User> findByFullnameContaining(String searchText, Pageable pageable);