ВНУТРЕННЕЕ соединение занимает слишком много времени

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

Проблема в том, что у меня есть запрос, который даже с INNER JOIN занимает не менее 5 секунд, и мне интересно, есть ли более быстрый способ сделать это. Вот ответ, который мне дали:

` q = "SELECT DISTINCT e2.eventId FROM event_tags e1 INNER JOIN event_tags e2 " \
        "ON BINARY e2.tagName=e1.tagName AND e2.eventId != e1.eventId " \
        "WHERE e1.eventId = {} ORDER BY RAND() LIMIT {}".format(eventId, '10')`

моя таблица тегов выглядит так

mysql> describe event_tags;

+---------+------------------+------+-----+---------+----------------+
| Field   | Type             | Null | Key | Default | Extra          |
+---------+------------------+------+-----+---------+----------------+
| tagId   | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| tagName | text             | NO   |     | NULL    |                |
| eventId | int(10) unsigned | NO   | PRI | NULL    |                |
+---------+------------------+------+-----+---------+----------------+

3 rows in set (0.00 sec)

а у меня в них куча тегов и они будут только расти дальше. Когда я делаю подсчет в таблице тегов, у меня есть 504 402 tagId, и то же самое для имени тега. Как я могу сделать взгляд быстрее?

Вот некоторые примеры данных таблицы тегов событий

mysql> select * from event_tags limit 40;
+-------+-------------------------------------------+---------+
| tagId | tagName                                   | eventId |
+-------+-------------------------------------------+---------+
|   261 | Justin Timberlake (Rescheduled from 11/9) |      38 |
|   264 | Rogers Arena                              |      38 |
|   267 | Pop                                       |      38 |
|   271 | Rock                                      |      38 |
|   285 | Justin Timberlake (Rescheduled from 11/8) |      41 |
|   288 | Rogers Arena                              |      41 |
|   291 | Pop                                       |      41 |
|   294 | Rock                                      |      41 |
|   595 | Yogesh Soman                              |      84 |
|   599 | Geetanjali Kulkarni                       |      84 |
|   602 | Bhagyashree Shankpal                      |      84 |
|   606 | Lalit Prabhakar                           |      84 |
|   611 | Sameer Sanjay Vidwans                     |      84 |
|   617 | Drama                                     |      84 |
|   647 | Shrihari Abhyankar                        |      89 |
|   651 | Deepali Borkar                            |      89 |
|   654 | Akash Kamble                              |      89 |
|   657 | Sharavi Kulkarni                          |      89 |
|   660 | Sharav Wadhawekar                         |      89 |
|   667 | Nipun Dharmadhikari                       |      89 |
|   670 | Drama                                     |      89 |
|   689 | Frank Grillo                              |      94 |
|   692 | Jamie Bell                                |      94 |
|   695 | Margaret Qualley                          |      94 |
|   700 | James Badge Dale                          |      94 |
|   704 | Tim Sutton                                |      94 |
|   710 | Drama                                     |      94 |
|   734 | Bruce Dern                                |     101 |
|   739 | Anthony Michael Hall                      |     101 |
|   745 | Sean Astin                                |     101 |
|   749 | Aly Michalka                              |     101 |
|   754 | Victoria Smurfit                          |     101 |
|   759 | Carl Bessai                               |     101 |
|   762 | Drama                                     |     101 |
|   783 | Sarah Clarke                              |     106 |
|   785 | Xander Berkeley                           |     106 |
|   787 | Kristen Gutoskie                          |     106 |
|   790 | Mackenzie Astin                           |     106 |
|   794 | Bobby Campo                               |     106 |
|   798 | Adam Cushman                              |     106 |
+-------+-------------------------------------------+---------+
40 rows in set (0.00 sec)

а вот оператор CREATE для таблицы:

CREATE TABLE IF NOT EXISTS event_tags(
    tagId INT UNSIGNED NOT NULL AUTO_INCREMENT,
    tagName VARCHAR(40) NOT NULL,
    eventId INT UNSIGNED NOT NULL,
    PRIMARY KEY(tagId, eventId)
);

Вот EXPLAIN для запроса:

mysql> EXPLAIN SELECT DISTINCT e2.eventId FROM event_tags e1 INNER JOIN event_tags e2 ON BINARY e2.tagName=e1.tagName AND e2.eventId != e1.eventId WHERE e1.eventId = 487 ORDER BY RAND() LIMIT 10
    -> ;
+----+-------------+-------+------+---------------+------+---------+------+-------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows  | Extra                                        |
+----+-------------+-------+------+---------------+------+---------+------+-------+----------------------------------------------+
|  1 | SIMPLE      | e1    | ALL  | NULL          | NULL | NULL    | NULL | 34275 | Using where; Using temporary; Using filesort |
|  1 | SIMPLE      | e2    | ALL  | NULL          | NULL | NULL    | NULL | 34275 | Using where; Using join buffer               |
+----+-------------+-------+------+---------------+------+---------+------+-------+----------------------------------------------+
2 rows in set (0.03 sec)

ОБНОВЛЕНИЕ: я создал индекс в таблице с помощью:

CREATE INDEX tagsNdx ON event_tags (eventId, tagName(255));

Что сейчас выглядит так:

mysql> show index from event_tags; +------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | +------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | event_tags | 0 | PRIMARY | 1 | tagId | A | 455408 | NULL | NULL | | BTREE | | | | event_tags | 0 | PRIMARY | 2 | eventId | A | 455408 | NULL | NULL | | BTREE | | | | event_tags | 1 | tagsNdx | 1 | eventId | A | 186 | NULL | NULL | | BTREE | | | | event_tags | 1 | tagsNdx | 2 | tagName | A | 186 | 255 | NULL | | BTREE | | | +------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 4 rows in set (0.00 sec) Но все равно медленно.

Может помочь составной индекс для некоторой комбинации (имя тега, идентификатор события). А еще это MyISAM, что сейчас совсем немодно. Возможно, стоит переключиться на InnoDB и использовать ИИ только на tagid.

Strawberry 25.02.2019 18:45

@Strawberry Я думал, что, поскольку eventId уже был первичным ключом, поиск будет достаточно быстрым.

stingMantis 25.02.2019 18:52

Вы пытаетесь соединить каждую строку с каждой другой строкой с тем же именем, а затем упорядочить весь промежуточный результат случайным образом; если эти tagNames не повторяются очень часто, я ожидаю, что этот тип запроса будет экспоненциально ухудшаться по мере роста таблицы ... хотя индексирование tagName, вероятно, немного поможет.

Uueerdo 25.02.2019 18:53

@Uueerdo на самом деле он только объединяет строки с одним и тем же тегом. Итак, пока есть индекс для tagName, должно быть быстро

Juan Carlos Oropeza 25.02.2019 18:57

@JuanCarlosOropeza в представленном ими запросе нет сравнения tagId.

Uueerdo 25.02.2019 18:59

Я видел ваш связанный вопрос, и там вы используете LIKE '% ... %', что сравнение не может использовать индекс и будет медленным

Juan Carlos Oropeza 25.02.2019 18:59

@Uueerdo есть e2.tagName=e1.tagName

Juan Carlos Oropeza 25.02.2019 18:59

@JuanCarlosOropeza да, но для tagName нет ограничений или индексов.

Uueerdo 25.02.2019 19:00

@stingMantis Можете ли вы добавить несколько примеров данных к своему вопросу? и фактический оператор CREATE для таблицы.

Uueerdo 25.02.2019 19:02

Глядя на ваш первоначальный вопрос, похоже, что ответ, который вы получили, действительно ваш лучший вариант; условие LIKE с ведущим подстановочным знаком почти всегда будет иметь низкую производительность.

Uueerdo 25.02.2019 19:06

Спасибо всем за ответы. Я добавил оператор создания и несколько примеров данных из таблицы.

stingMantis 25.02.2019 19:12

Как уже было сказано, пожалуйста, разместите EXPLAIN SELECT .... Также я думаю, что ORDER BY RAND() создает медленную сортировку файлов.

Atle 25.02.2019 19:17

Просто создайте индекс CREATE INDEX idx1 ON event_tags (eventId , tagName)

Juan Carlos Oropeza 25.02.2019 19:19

@JuanCarlosOropeza Это все еще нормально, учитывая, что tagId и eventId уже являются первичными ключами?

stingMantis 25.02.2019 19:22

Я просто редактирую свой комментарий, потому что у вас есть фильтр e1.eventId = 487 лучше составной индекс с (eventId , tagName)

Juan Carlos Oropeza 25.02.2019 19:24

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

stingMantis 25.02.2019 20:25
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
0
16
62
1

Ответы 1

Возможна следующая оптимизация:

  1. Удалите столбец «eventId» из первичного ключа (этот шаг является необязательным и может быть доработан, если хотите).
  2. Создайте индекс для столбца (eventId,tag_name).
  3. Выполнить команду: ANALYZE TABLE event_tags

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

stingMantis 25.02.2019 20:20

Стоимость и время запроса должны уменьшиться после создания индекса, даже если это не очень существенно, иначе индекс не будет использоваться. Кроме того, после удаления кеша сеанса следует брать время до и после, иначе данные будут повторно использоваться из кеша и не будут давать истинного сравнения.

Ahmed Mustafa 25.02.2019 20:33

Также, пожалуйста, сообщите, сколько различных идентификаторов событий и сколько различных tag_name в таблице

Ahmed Mustafa 25.02.2019 20:35

в наборе 7266 строк (0,00 сек) для идентификаторов событий и 12346 строк в наборе (0,01 сек) для tagName. Думаете, мне придется рефакторить эту таблицу?

stingMantis 25.02.2019 21:29

в наборе 117792 строки (0,19 секунды) для идентификаторов событий и 105008 строк в наборе (2,11 секунды) для tagName. Думаете, мне придется рефакторить эту таблицу? EDIT: ДОБАВЛЕНЫ ПРАВИЛЬНЫЕ ЗНАЧЕНИЯ ДЛЯ eventId и tagName

stingMantis 25.02.2019 21:35

Наш новый индекс не используется, и тому может быть много причин, в том числе и старая статистика. Используйте команду: ANALYZE TABLE event_tags

Ahmed Mustafa 25.02.2019 21:58

mysql> проанализировать таблицу event_tags; +----------------------+---------+-----------+----- -----+ | Таблица | Оп | Сообщение_тип | Сообщение_текст | +----------------------+---------+-----------+----- -----+ | <dbname>.event_tags | анализировать | статус | ОК | +----------------------+---------+-----------+----- -----+ 1 ряд в наборе (0,00 сек)

stingMantis 25.02.2019 22:04

Другие вопросы по теме