Я пытаюсь заставить этот запрос работать, который выбирает канал для пользователя, который интересуется несколькими тегами (так называемые пабы). Сопоставление пользователя и тега находится в таблице 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 тыс. Строк каждая.