在数据库中查找用户的SQL查询的性能

时间:2018-12-20 14:02:47

标签: sql postgresql performance spring-data-jpa

我正在开发应用程序,并且正在使用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运算符,并且还大量使用了一些函数,例如UPPERCONCAT 。我正在使用PostgreSQL。

能否请您评估一下这种查询在大量记录上是否表现良好?你能解释为什么/为什么不吗?您有任何改进技巧吗?

非常感谢!

2 个答案:

答案 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子句中使用函数:

https://www.mssqltips.com/sqlservertip/1236/avoid-sql-server-functions-in-the-where-clause-for-performance/

或者,您可以将另一个字段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);