このクエリの最適化について助けが必要です。
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
制限がない場合、このクエリは 20 万行を返し、実行に約 1.3 ~ 2 秒かかります。問題は order by 句にあるようです。これがないと、クエリに .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 秒で実行されます。非常に素晴らしい改善ですが、改善できるかどうか知りたいです。どうにかして2番目の内部結合をフィルタリングできれば、物事はより速くなるようです。
ありがとう。
スキーマ:
messages
message_id, entity_id, message, timestamp
subscription
user_id, entity_id
アップデート
Raymond Nijland's Answer は私の最初の問題を解決しますが、別の問題が発生しました
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
次の 2 つの場合、直接結合は非効率的です。
サブスクリプション テーブルに 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