MySQL Оптимизация запросов для подсчета запросов - PullRequest
0 голосов
/ 05 февраля 2020

Мне нужна помощь с оптимизацией для этого запроса. Вот таблицы:

activities
- activity_id (PRIMARY)
- item_id
- user_id
- created_at

INDEX: user_id_created_at (user_id, created_at)
INDEX: item_id (item_id)
retail_activities
- activity_id (PRIMARY)
- item_id
- created_at

INDEX: item_id (activity_id, item_id)
INDEX: item_id_created (activity_id, item_id, created_at)
users
- user_id (PRIMARY)
- is_private

INDEX: user_id_private (user_id, is_private)

Цель

Я хотел бы найти количество элементов и уникальных пользователей в retail_activities, которые произошли за диапазон дат, в котором таблица item_id в действиях не равна item_id в таблицах retail_activities, а пользователь не является личным.

По сути, я хочу найти общее количество операций в рознице что произошло, и общее количество уникальных пользователей, которые выполнили для выбранного item_id и выбранного диапазона времени.

Таким образом, запрос будет (X является целым числом, например, 1234 - это идентификатор, если элемент)

SELECT count(retail_activities.item_id) as total_items, count(distinct activities.user_id) as total_users 
from activities 
inner join retail_activities on retail_activities.activity_id = activities.activity_id 
inner join users on users.user_id = activities.user_id 
where users.is_private = 0 and 
activities.item_id != retail_activities.item_id and retail_activities.item_id = X and
retail_activities.created_at > "2019-11-22 00:00:00"

ОБЪЯСНЕНИЕ этого запроса следующее:

1   SIMPLE  retail_activities   item_id_created item_id_created 5   const   812856  Using where; Using index
1   SIMPLE  activities  eq_ref  PRIMARY PRIMARY 4   retail_activities.activity_id   1   Using where
1   SIMPLE  users   eq_ref  PRIMARY PRIMARY 4   activities.user_id  1   Using where

Поскольку у этого элемента много действий (350 КБ), он выполняется очень медленно (8-25 с). Есть ли способ ускорить это?

Ответы [ 2 ]

1 голос
/ 05 февраля 2020

Для этого запроса:

select count(*) as total_items, count(distinct a.user_id) as total_users 
from activities a join
     retail_activities ra
     on ra.activity_id = a.activity_id join
     users u
     on u.user_id = a.user_id 
where u.is_private = 0 and 
      a.item_id <> ra.item_id and
      ra.item_id = X
      ra.created_at > '2019-11-22';

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

  • retail_activities(item_id, created_at, activity_id)
  • activities(activity_id, item_id) (не требуется, если activity_id является первичным ключом)
  • users(user_id, is_private)
0 голосов
/ 05 февраля 2020

Я предлагаю вам оптимизировать свою стратегию индексирования и попытаться использовать индекс ha sh везде, где вы можете.

Согласно документации MySQL:

В качестве альтернативы составной индекс, вы можете ввести столбец, который «хэшируется» на основе информации из других столбцов. Если этот столбец короткий, достаточно уникальный и индексированный, он может быть быстрее, чем «широкий» индекс для многих столбцов.

Кроме того, вам не нужно INDEX: item_id (activity_id, item_id) в retail_activities таблица явно. Это потому, что вы уже создали составной первичный ключ, включающий их. Так что это будет выступать в качестве индекса.

И, чтобы посмотреть на оптимизацию слияния индекса. Вот MySQL журнал до c. И прочитайте переключатель оптимизатора , чтобы определить идеальный порядок объединения для достижения максимальной производительности. Вот некоторая информация, которую, я думаю, вы найдете полезной:

Изменить порядок соединения. Способы выполнения sh, включая подсказки оптимизатора порядка соединения (см. Раздел 8.9.3, «Советы оптимизатора»), STRAIGHT_JOIN, следующий сразу за SELECT, и оператор соединения STRAIGHT_JOIN.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...