我需要帮助来优化此查询。
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
如果没有限制,此查询将返回 200K 行,运行大约需要 1.3 - 2 秒。问题似乎出在 order by 子句中。没有它,查询需要 .0005 seconds 。
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
这在 0.12 秒内运行。一个非常好的改进,但我想知道它是否可以更好。似乎如果我能以某种方式过滤第二个内部连接,那么事情会更快。
谢谢。
架构:
messages
message_id, entity_id, message, timestamp
subscription
user_id, entity_id
更新
Raymond 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 条目
消息表中的相关条目很少
对于如何解决这个问题,有任何的建议吗?如果不是从查询的角度来看,一个应用程序?
更新
解释信息
限制 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