[Mysql] Ускорить запрос
От: rosencrantz США  
Дата: 03.07.21 17:19
Оценка:
База Mysql 8.0.19.

Есть таблица вида:
create table Users(
  orgId varchar(64) not null,
  id varchar(64) not null,
  firstName varchar(64) not null,
  lastName varchar(64) not null,
  primary key (orgId, id)
)


В таблице — 45 млн записей. orgId — 200 уникальных значений. На один orgId приходится 225 тыс записей. Хочется быстро выполнять вот такие 2 запроса:
-- Q1:
select * from Users where orgId = '123' and firstName like 'a%' and lastName like 'b%'

-- Q2:
select * from Users where orgId = '123' and (firstName like 'a%' or lastName like 'a%')


В обоих случаях 'a%' и 'b%' — это ввод пользователя. Пользователь может ввести 'j' ('j%'), а может 'jonathan' ('jonathan%').

Сделал индекс:
create index OrgIdFirstNameLastName on Users(orgId, firstName, lastName)


Индекс применяется для Q1, запрос работает быстро. Для Q2 не применяется, Mysql использует PRIMARY. Q2 сильно медленнее Q1.

Если добавить "use index":
-- Q2_B:
select * from Users use index (OrgIdFirstNameLastName) 
where orgId = '123' and (firstName like 'a%' or lastName like 'a%')


Q2_B всё равно работает медленно.

Как добиться, чтобы Q2 работал быстро?
Отредактировано 09.07.2021 18:00 rosencrantz . Предыдущая версия . Еще …
Отредактировано 03.07.2021 17:21 rosencrantz . Предыдущая версия .
Re: (Mysql) Ускорить запрос
От: L.K. Марс  
Дата: 03.07.21 17:50
Оценка:
R> orgId varchar(64) not null,
R> id varchar(64) not null,

Зачем тут varchar? Заменить на char, на лучше на int.

R>select * from Users where orgId = '123' and firstName like 'a%' and lastName like 'b%'


Создать два индекса: orgId,firstName,lastName и orgId,lastName

R>select * from Users where orgId = '123' and (firstName like 'a%' or lastName like 'a%')


select * from Users where ( orgId = '123' and firstName like 'a%' ) or ( orgId = '123' and lastName like 'a%' )
Re[2]: (Mysql) Ускорить запрос
От: rosencrantz США  
Дата: 03.07.21 18:08
Оценка:
Здравствуйте, L.K., Вы писали:

LK>Создать два индекса: orgId,firstName,lastName и orgId,lastName


Попробовал — использует PRIMARY всё равно.

LK>select * from Users where ( orgId = '123' and firstName like 'a%' ) or ( orgId = '123' and lastName like 'a%' )


Ну он не настолько глупый же (попробовал, нет разницы)
Re[3]: (Mysql) Ускорить запрос
От: L.K. Марс  
Дата: 03.07.21 18:23
Оценка:
Тогда план запросов — в студию.
Re[3]: (Mysql) Ускорить запрос
От: L.K. Марс  
Дата: 03.07.21 18:32
Оценка:
И вообще, что значит "работает медленно"? Сколько оно выполняется?
Re: (Mysql) Ускорить запрос
От: BlackEric http://black-eric.lj.ru
Дата: 03.07.21 20:49
Оценка: +4
Здравствуйте, rosencrantz, Вы писали:

R>-- Q2:

R>select * from Users where orgId = '123' and (firstName like 'a%' or lastName like 'a%')
R>[/code]

R>Как добиться, чтобы Q2 работал быстро?


Попробуйте заменить or на union select
https://github.com/BlackEric001
Re[2]: (Mysql) Ускорить запрос
От: rosencrantz США  
Дата: 04.07.21 15:44
Оценка:
Здравствуйте, BlackEric, Вы писали:

BE>Здравствуйте, rosencrantz, Вы писали:


R>>-- Q2:

R>>select * from Users where orgId = '123' and (firstName like 'a%' or lastName like 'a%')
R>>[/code]

R>>Как добиться, чтобы Q2 работал быстро?


BE>Попробуйте заменить or на union select


Индекс по (orgId,firstName,lastName) применяется только для случаев выборки по (orgId), (orgId,firstName), (orgId,firstName,lastName). Для случая (orgId,lastName) он не применяется.

Если кроме индекса (orgId,firstName,lastName) добавить ещё (orgId,lastName), запросы:

-- Q3:
select * from Users where orgId = '123' and firstName like 'a%'

-- Q4:
select * from Users where orgId = '123' and lastName like 'a%'


работают быстро (и union конечно тоже). Но у меня к сожалению нет возможности заменить where/or на select/union/select. Эти запросы строит ORM по куче параметров, приходящих снаружи, и хочется по возможности избежать разной логики "для этого" и "для всего кроме этого".

Если не получится решить проблему какими-то хитрыми индексами или любым другим "общим" решением, скорее всего буду делать отдельный API под этот конкретный запрос.
Re[3]: (Mysql) Ускорить запрос
От: BlackEric http://black-eric.lj.ru
Дата: 04.07.21 15:50
Оценка: 3 (1) +1
Здравствуйте, rosencrantz, Вы писали:

R>Если не получится решить проблему какими-то хитрыми индексами или любым другим "общим" решением, скорее всего буду делать отдельный API под этот конкретный запрос.


Or почти всегда просаживает производительность. И заставить его использовать индексы не получается.
В этом случае вам нужно копать в сторону того что бы заставить ORM генерить запрос по другому. Ну или если ваш ORM позволяет, то заставьте тут выполнять запрос напрямую, без генерации.
https://github.com/BlackEric001
Re: (Mysql) Ускорить запрос
От: romangr Россия  
Дата: 04.07.21 16:04
Оценка:
Здравствуйте, rosencrantz, Вы писали:

R>База Mysql 8.0.19.


R>Есть таблица вида:

R>
R>create table Users(
R>  orgId varchar(64) not null,
R>  id varchar(64) not null,
R>  firstName varchar(64) not null,
R>  lastName varchar(64) not null,
R>  primary key (orgId, id)
R>)
R>


R>Как добиться, чтобы Q2 работал быстро?


Возможно, следует сделать 2 индекса —
1. create index OrgIdFirstName on Users(orgId, firstName)
2. create index OrgIdLastName on Users(orgId, lastName)
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.