Mysql 5.7 запрос с внутренним соединением и порядком по первичному ключу очень медленный - PullRequest
3 голосов
/ 04 июля 2019

Я пытаюсь заставить этот запрос работать, который выбирает канал для пользователя, который интересуется несколькими тегами (так называемые пабы). Сопоставление пользователя и тега находится в таблице user_pub, а сами сообщения имеют pub_id. Схемы ниже.

CREATE TABLE `post` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `pub_id` bigint(20) unsigned NOT NULL,
  `author_id` bigint(20) unsigned NOT NULL,
  `snippet` text COLLATE utf8mb4_unicode_ci,
  `type` tinyint(3) unsigned NOT NULL,
  `status` tinyint(3) unsigned NOT NULL DEFAULT '1',
  `time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `time_idx` (`time`),
  KEY `fk_author_id_idx` (`author_id`),
  KEY `idx_pub_status_type_author` (`pub_id`,`type`,`status`,`author_id`)
) ENGINE=InnoDB AUTO_INCREMENT=299521 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

CREATE TABLE `user_pub` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `user_id` bigint(20) unsigned NOT NULL,
  `pub_id` bigint(20) unsigned NOT NULL,
  `join_status` tinyint(4) NOT NULL DEFAULT '1',
  `time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_unq_up_user_pub` (`user_id`,`pub_id`)
) ENGINE=InnoDB AUTO_INCREMENT=227392 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

Запрос прост:

SELECT p.*
FROM post p
INNER JOIN user_pub up ON up.pub_id = p.pub_id
WHERE up.user_id = 1234
ORDER BY p.id DESC LIMIT 10;

Без ORDER BY, это быстро (0,5 мс), объяснение выглядит нормально:

+----+-------------+-------+----------------------------+----------------------------+---------+-----------------------+------+----------+-------------+
| id | select_type | table | possible_keys              | key                        | key_len | ref                   | rows | filtered | Extra       |
+----+-------------+-------+----------------------------+----------------------------+---------+-----------------------+------+----------+-------------+
|  1 | SIMPLE      | up    | idx_unq_up_user_pub        | idx_unq_up_user_pub        | 8       | const                 |    2 |   100.00 | Using index |
|  1 | SIMPLE      | p     | idx_pub_status_type_author | idx_pub_status_type_author | 8       | thedb.up.pub_id       |   64 |   100.00 | NULL        |
+----+-------------+-------+----------------------------+----------------------------+---------+-----------------------+------+----------+-------------+

С ORDER BY требуется ~ 70 мс и объяснение имеет Использование индекса; Используя временные; Использование сортировки файлов в EXTRA:

+----+-------------+-------+----------------------------+----------------------------+---------+-----------------------+------+----------+----------------------------------------------+
| id | select_type | table | possible_keys              | key                        | key_len | ref                   | rows | filtered | Extra                                        |
+----+-------------+-------+----------------------------+----------------------------+---------+-----------------------+------+----------+----------------------------------------------+
|  1 | SIMPLE      | up    | idx_unq_up_user_pub        | idx_unq_up_user_pub        | 8       | const                 |    2 |   100.00 | Using index; Using temporary; Using filesort |
|  1 | SIMPLE      | p     | idx_pub_status_type_author | idx_pub_status_type_author | 8       | thedb.up.pub_id       |   64 |   100.00 | NULL                                         |
+----+-------------+-------+----------------------------+----------------------------+---------+-----------------------+------+----------+----------------------------------------------+

Я пытался переписать этот запрос, как этот, и это никак не повлияло:

SELECT p1.* 
FROM post p1,
    (SELECT p.id
        FROM post p, user_pub up
        WHERE up.user_id = 1234 AND up.pub_id = p.pub_id
    ) p2
WHERE p1.id = p2.id
ORDER BY p1.id DESC LIMIT 10;

Подведем итог:

  • Я упорядочиваю по первичному ключу таблицы сообщений, поэтому он должен быть близок к 0,5 мс, чем 70 мс.
  • Я не могу понять, почему объяснение показывает temp, filesort и т. Д. В строке таблицы user_pub вместо таблицы post, если порядок по идентификатору записи.

Таблицы не большие, около 250 тыс. Строк каждая.

...