Производительность SQL-запроса для поиска пользователей в базе данных - PullRequest
0 голосов
/ 20 декабря 2018

Я занимаюсь разработкой приложения и использую 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.

Можете ли вы оценить, будет ли этот тип запроса работать на большом количестве записей?Можете ли вы попытаться объяснить, почему / почему нет?Есть ли у вас какие-либо советы по его улучшению?

Большое спасибо!

Ответы [ 2 ]

0 голосов
/ 20 декабря 2018

Как отмечено в комментариях, это, вероятно, очень медленно, потому что вы используете функции в предложении 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);

0 голосов
/ 20 декабря 2018

Я бы переписал запрос следующим образом:

SELECT * FROM users u
WHERE concat(' ', u.first_name,' ', u.last_name) ILIKE ' ' || :query || '%';

Вы должны создать индекс триграмм для поддержки этого:

CREATE EXTENSION pg_trgm;

CREATE INDEX ON users USING gin
   (concat(' ', u.first_name,' ', u.last_name) gin_trgm_ops);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...