MySQL - улучшение агрегации количества (*) с помощью составных индексных ключей - PullRequest
1 голос
/ 27 марта 2019

У меня есть таблица со следующей структурой с почти 120000 строками,

desc user_group_report +------------------+----------+------+-----+-------------------+-------+ | Field | Type | Null | Key | Default | Extra | +------------------+----------+------+-----+-------------------+-------+ | user_id | int | YES | MUL | NULL | | | group_id | int(11) | YES | MUL | NULL | | | type_id | int(11) | YES | | NULL | | | group_desc | varchar(128)| NO| | NULL | | status | enum('open','close')|NO| | NULL | | | last_updated | datetime | NO | | CURRENT_TIMESTAMP | | +------------------+----------+------+-----+-------------------+-------+

У меня есть индексы для следующих ключей:

  • user_group_type (user_id, group_id, group_type)
  • group_type (group_id, type_id)
  • user_type (user_id, type_id)
  • user_group (user_id, group_id)

Моя проблема в том, что я выполняю агрегацию count (*) в вышеуказанной группе таблиц по group_id и с предложением type_id

Вот запрос:

select count(*) user_count, group_id
from user_group_report
where type_id = 1
group by group_id;

, а вот объяснениеплан (запрос занимает в среднем 0,3 секунды):

+----+-------------+------------------+-------+---------------------------------+---------+---------+------+--------+--------------------------+
| id | select_type | table            | type  | possible_keys                   | key     | key_len | ref  | rows   | Extra                    |
+----+-------------+------------------+-------+---------------------------------+---------+---------+------+--------+--------------------------+
|  1 | SIMPLE      | user_group_report | index | user_group_type,group_type,user_group | group_type | 10      | NULL | 119811 | Using where; Using index |
+----+-------------+------------------+-------+---------------------------------+---------+---------+------+--------+--------------------------+

Здесь, насколько я понимаю, запрос почти выполняет полное сканирование таблицы из-за сложных индексов, а когда я пытаюсь добавить индекс для group_id, строки вПлан объяснения показывает меньшее число (почти половину строк), но время, затрачиваемое на выполнение запроса, увеличивается до 0,4–0,5 с.

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

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

PS: IЯ уже пытался изменить запрос следующим образом, но не смог найти улучшения.

select count(user_id) user_count, group_id
from user_group_report
where type_id = 1
group by group_id;

Любая небольшая помощь приветствуется.

Редактировать:

В соответствии с предложениями я добавил новый индекс

type_group on (type_id, group_id)

Это новый план объяснения.Количество строк в объяснении уменьшено, но время выполнения запроса остается тем же

+----+-------------+------------------+------+---------------------------------+---------+---------+-------+-------+--------------------------+
| id | select_type | table            | type | possible_keys                   | key     | key_len | ref   | rows  | Extra                    |
+----+-------------+------------------+------+---------------------------------+---------+---------+-------+-------+--------------------------+
|  1 | SIMPLE      | user_group_report | ref  | user_group_type,type_group,user_group | type_group | 5       | const | 59846 | Using where; Using index |
+----+-------------+------------------+------+---------------------------------+---------+---------+-------+-------+--------------------------+

РЕДАКТИРОВАТЬ 2: Добавление деталей, как предлагается в ответах / комментариях

select count(*)
from user_group_report
where type_id = 1

Самому запросу требуется 0,25 секунды для выполнения.

и вот план объяснения:

+----+-------------+------------------+------+---------------+---------+---------+-------+-------+-------------+
| id | select_type | table            | type | possible_keys | key     | key_len | ref   | rows  | Extra       |
+----+-------------+------------------+------+---------------+---------+---------+-------+-------+-------------+
|  1 | SIMPLE      | user_group_report | ref  | type_group       | type_group | 5       | const | 59866 | Using index |
+----+-------------+------------------+------+---------------+---------+---------+-------+-------+-------------+

Ответы [ 3 ]

3 голосов
/ 27 марта 2019

Я считаю, что ваш group_type не так.Попробуйте переключить атрибуты.

create index ix_type_group on user_group_report(type_id,group_id)

Этот индекс лучше подходит для вашего запроса, поскольку вы указываете type_id = 1 в предложении where.Поэтому обработчик запросов находит первую запись с type_id = 1 в вашем индексе, а затем сканирует записи в индексе с этим type_id и выполняет агрегирование.С таким индексом доступны только соответствующие записи в индексе, что невозможно с индексом group_type.

1 голос
/ 27 марта 2019

Если type_id является выборочным (т. Е. Значительно сокращает пространство поиска), создание индекса на type_id, group_id должно значительно помочь.

Это потому, что это уменьшает количество записей, которые должны быть сгруппированы в первую очередь (удалите все, где type_id! = 1), и только после этого производится группировка / суммирование.

РЕДАКТИРОВАТЬ:

Исходя из комментариев, кажется, нам нужно выяснить больше о том, где узкое местоis - поиск записей или группировка / суммирование.

Первым шагом будет измерение производительности:

select count(*)
from user_group_report
where type_id = 1

Если это значительно быстрее, проблема, скорее всего, в группировкечем в поиске записей.Если это так же медленно, это в первую очередь поиск записей.

0 голосов
/ 18 апреля 2019

Действительно ли большинство столбцов должно быть NULLable?Измените на NOT NULL, где это применимо.

Какой процент таблицы имеет type_id = 1?Если это большая часть таблицы, то это объясняет, почему вы не видите большого улучшения.Между тем, EXPLAIN, кажется, думает, что есть только два различных значения для type_id, следовательно, он говорит, что будет сканироваться только половина таблицы - этому номеру нельзя доверять .

Чтобы получить более полное представление о происходящем, выполните следующие действия:

EXPLAIN FORMAT=JSON SELECT...;

И

FLUSH STATUS;
SELECT ...
SHOW SESSION STATUS LIKE 'Handler%';

Мы можем помочь в интерпретации полученных вами данных.( Здесь - краткое изложение этого.)

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