Я задал исходный вопрос здесь в стеке раньше. Извините, если это не лучший способ сделать это.
Проблема в том, что у меня есть запрос, который даже с 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)
Но все равно медленно.
@Strawberry Я думал, что, поскольку eventId уже был первичным ключом, поиск будет достаточно быстрым.
Вы пытаетесь соединить каждую строку с каждой другой строкой с тем же именем, а затем упорядочить весь промежуточный результат случайным образом; если эти tagNames не повторяются очень часто, я ожидаю, что этот тип запроса будет экспоненциально ухудшаться по мере роста таблицы ... хотя индексирование tagName, вероятно, немного поможет.
@Uueerdo на самом деле он только объединяет строки с одним и тем же тегом. Итак, пока есть индекс для tagName, должно быть быстро
@JuanCarlosOropeza в представленном ими запросе нет сравнения tagId.
Я видел ваш связанный вопрос, и там вы используете LIKE '% ... %', что сравнение не может использовать индекс и будет медленным
@Uueerdo есть e2.tagName=e1.tagName
@JuanCarlosOropeza да, но для tagName нет ограничений или индексов.
@stingMantis Можете ли вы добавить несколько примеров данных к своему вопросу? и фактический оператор CREATE для таблицы.
Глядя на ваш первоначальный вопрос, похоже, что ответ, который вы получили, действительно ваш лучший вариант; условие LIKE с ведущим подстановочным знаком почти всегда будет иметь низкую производительность.
Спасибо всем за ответы. Я добавил оператор создания и несколько примеров данных из таблицы.
Как уже было сказано, пожалуйста, разместите EXPLAIN SELECT .... Также я думаю, что ORDER BY RAND() создает медленную сортировку файлов.
Просто создайте индекс CREATE INDEX idx1 ON event_tags (eventId , tagName)
@JuanCarlosOropeza Это все еще нормально, учитывая, что tagId и eventId уже являются первичными ключами?
Я просто редактирую свой комментарий, потому что у вас есть фильтр e1.eventId = 487 лучше составной индекс с (eventId , tagName)
Индекс звучит как хорошая идея. Я обновил свой исходный вопрос, чтобы показать, как я его добавил, но, к сожалению, для получения результатов по-прежнему требуется около 5 секунд. Есть ли что-то, что я делаю неправильно здесь?






Возможна следующая оптимизация:
Я обновил свой пост, чтобы показать таблицу после добавления индекса. Я все еще получаю медленные результаты, хотя.
Стоимость и время запроса должны уменьшиться после создания индекса, даже если это не очень существенно, иначе индекс не будет использоваться. Кроме того, после удаления кеша сеанса следует брать время до и после, иначе данные будут повторно использоваться из кеша и не будут давать истинного сравнения.
Также, пожалуйста, сообщите, сколько различных идентификаторов событий и сколько различных tag_name в таблице
в наборе 7266 строк (0,00 сек) для идентификаторов событий и 12346 строк в наборе (0,01 сек) для tagName. Думаете, мне придется рефакторить эту таблицу?
в наборе 117792 строки (0,19 секунды) для идентификаторов событий и 105008 строк в наборе (2,11 секунды) для tagName. Думаете, мне придется рефакторить эту таблицу? EDIT: ДОБАВЛЕНЫ ПРАВИЛЬНЫЕ ЗНАЧЕНИЯ ДЛЯ eventId и tagName
Наш новый индекс не используется, и тому может быть много причин, в том числе и старая статистика. Используйте команду: ANALYZE TABLE event_tags
mysql> проанализировать таблицу event_tags; +----------------------+---------+-----------+----- -----+ | Таблица | Оп | Сообщение_тип | Сообщение_текст | +----------------------+---------+-----------+----- -----+ | <dbname>.event_tags | анализировать | статус | ОК | +----------------------+---------+-----------+----- -----+ 1 ряд в наборе (0,00 сек)
Может помочь составной индекс для некоторой комбинации (имя тега, идентификатор события). А еще это MyISAM, что сейчас совсем немодно. Возможно, стоит переключиться на InnoDB и использовать ИИ только на tagid.