【发布时间】:2013-10-05 17:18:23
【问题描述】:
我需要帮助来优化此查询。
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 子句中。没有它,查询需要 0.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
这将在 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
【问题讨论】:
-
你能发布 show create table 语句吗?
-
单个用户20万行?你确定吗?
-
@DanBracuk 是的,我确定
-
你能在没有 user_id 的情况下运行 EXPLAIN 并且在消息的情况下很少相关条目并在此处发布结果吗?
-
如果您希望我们帮助优化查询,您需要向我们展示表和索引定义,以及每个表的行数。也许您的表格定义不佳。也许索引没有正确创建。也许您认为您在该列上没有索引。没有看到表和索引定义,我们无法判断。我们还需要行计数,因为这会极大地影响查询优化。如果您知道如何处理
EXPLAIN或获取执行计划,请将结果也放入问题中。
标签: mysql sql database database-design