Мне нужна помощь в оптимизации этого запроса.Оптимизация порядка заказа по запросу соединения
SELECT messages.*
FROM messages
INNER JOIN subscription ON subscription.entity_id = messages.entity_id
WHERE subscription.user_id = 1
ORDER BY messages.timestamp DESC
LIMIT 50
Без лимита этот запрос возвращает 200 тыс. Строк и занимает около 1,3-2 секунды для запуска. Проблема, по-видимому, в порядке выполнения. Без него запрос занимает .0005 секунд.
Indexes:
(subscription.user_id, subscription.entity_id)
(subscription.entity_id)
(messages.timestamp)
(messages.entity_id, messages.timestamp)
я был в состоянии улучшить производительность, изменив запрос следующим образом:
SELECT messages.* FROM messages
INNER JOIN subscription ON subscription.entity_id = messages.entity_id
INNER JOIN (
SELECT message_id FROM messages ORDER BY timestamp DESC
) as temp on temp.messsage_id = messages.message_id
WHERE subscription.user_id = 1 LIMIT 50
Это работает в .12 секунды. Очень приятное улучшение, но я хотел бы знать, может ли это быть лучше. Кажется Если бы я мог каким-то образом отфильтровать второе внутреннее соединение, тогда все будет быстрее.
Спасибо.
SCHEMA:
messages
message_id, entity_id, message, timestamp
subscription
user_id, entity_id
UPDATE
Ответ Раймонд Nijland в решает мою исходную задачу, а другие просто всплыл
SELECT messages.*
FROM messages
STRAIGHT_JOIN subscription ON subscription.entity_id = messages.entity_id
WHERE subscription.user_id = 1
ORDER BY messages.timestamp DESC
LIMIT 50
Прямого соединение является неэффективным в двух случаях:
нет запись user_id в таблице подписки
есть несколько соответствующих записей в таблице сообщений
Любые предложения о том, как это исправить? если не с точки зрения запроса, одно приложение?
UPDATE
EXPLAIN INFO
LIMIT 50
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
| 1 | SIMPLE | messages | index | idx_timestamp | idx_timestamp | 4 | NULL | 50 | |
| 1 | SIMPLE | subscription | eq_ref | PRIMARY,entity_id,user_id | PRIMARY | 16 | const, messages.entity_id | 1 | Using index |
Без предела
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
| 1 | SIMPLE | messages | ALL | entity_id_2,entity_id | NULL | NULL | NUL | 255069 | Using filesort|
| 1 | SIMPLE | subscription | eq_ref | PRIMARY,entity_id,user_id | PRIMARY | 16 | const, messages.entity_id | 1 | Using index |
СОЗДАТЬ ТАБЛИЦА ЗАЯВЛЕНИЙ:
С ~ 5000 строк
subscription | CREATE TABLE `subscription` (
`user_id` bigint(20) unsigned NOT NULL,
`entity_id` bigint(20) unsigned NOT NULL,
PRIMARY KEY (`user_id`,`entity_id`),
KEY `entity_id` (`entity_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
с ~ 255,000 строк
messages | CREATE TABLE `messages` (
`message_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`entity_id` bigint(20) unsigned NOT NULL,
`message` varchar(255) NOT NULL DEFAULT '',
`timestamp` int(10) unsigned NOT NULL,
PRIMARY KEY (`message_id`),
KEY `entity_id` (`entity_id`,`timestamp`),
KEY `idx_timestamp` (`timestamp`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
Вы можете разместить шоу создать заявление таблицы? –
200 тысяч строк для одного пользователя? Вы уверены, что? –
@ DanBracuk yes Я уверен –