このクエリを最適化しようとしています:
SELECT `posts`.* FROM `posts` INNER JOIN `posts_tags` ON `posts`.id = `posts_tags`.post_id WHERE (((`posts_tags`.tag_id = 1))) ORDER BY posts.created_at DESC;
テーブルのサイズは 38k 行で、31k と mysql は "filesort" を使用するため、かなり遅くなります。別のインデックスを使用しようとしましたが、うまくいきませんでした。
CREATE TABLE `投稿` ( `id` int(11) NOT NULL auto_increment, `created_at`日時デフォルトNULL、 主キー (`id`)、 KEY `index_posts_on_created_at` (`created_at`), KEY `for_tags` (`trashed`,`published`,`clan_private`,`created_at`) ) ENGINE=InnoDB AUTO_INCREMENT=44390 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci CREATE TABLE `posts_tags` ( `id` int(11) NOT NULL auto_increment, `post_id` int(11) デフォルト NULL、 `tag_id` int(11) デフォルト NULL、 `created_at`日時デフォルトNULL、 `updated_at` 日時デフォルト NULL、 主キー (`id`)、 KEY `index_posts_tags_on_post_id_and_tag_id` (`post_id`,`tag_id`) ) ENGINE=InnoDB AUTO_INCREMENT=63175 DEFAULT CHARSET=utf8
+----+-------------+------------+--------+-------- --------------+------------------------------+---- --+---------------------+-------+-------------- ----------------------------------------------+ | | ID | select_type | テーブル | タイプ | 可能な_キー | キー | key_len | 参照 | 行 | 行 エクストラ | +----+-------------+------------+--------+-------- --------------+------------------------------+---- --+---------------------+-------+-------------- ----------------------------------------------+ | | 1 | シンプル | 投稿タグ | インデックス | index_post_id_and_tag_id | index_post_id_and_tag_id | 10 | ヌル | 24159 | where を使用します。インデックスの使用; 一時的な使用; ファイルソートの使用 | | | 1 | シンプル | 投稿 | eq_ref | プライマリ | プライマリ | 4 | .posts_tags.post_id | 1 | | | +----+-------------+------------+--------+-------- --------------+------------------------------+---- --+---------------------+-------+-------------- ----------------------------------------------+ 2 行セット (0.00 秒)
filesort を使用して mysql を回避するには、どのような種類のインデックスを定義する必要がありますか? 注文フィールドがwhere句にない場合は可能ですか?
更新: プロファイリング結果:
mysql> クエリ 1 のプロファイルを表示します。 +--------------------------------+----------------------+ | | ステータス | 期間 | +--------------------------------+----------------------+ | | 開始 | 0.000027 | | | クエリのクエリ キャッシュをチェックする | 0.037953 | | | テーブルを開く | 0.000028 | | | システムロック | 0.010382 | | | テーブル ロック | 0.023894 | | | 初期化 | 0.000057 | | | 最適化 | 0.010030 | | | 統計 | 0.000026 | | | 準備中 | 0.000018 | | | tmp テーブルの作成 | 0.128619 | | | 実行中 | 0.000008 | | | tmp テーブルへのコピー | 1.819463 | | | ソート結果 | 0.001092 | | | データの送信 | 0.004239 | | | 終了 | 0.000012 | | | tmp テーブルの削除 | 0.000885 | | | 終了 | 0.000006 | | | 終了 | 0.000005 | | | クエリ終了 | 0.000006 | | | 結果をクエリキャッシュに保存 | 0.000005 | | | アイテム解放 | 0.000021 | | | テーブルを閉じる | 0.000013 | | | 遅いクエリのロギング | 0.000004 | | | クリーンアップ | 0.000006 | +--------------------------------+----------------------+
update2:
実際のクエリ (いくつかのブール フィールド、役に立たないインデックス)
SELECT `posts`.* FROM `posts` INNER JOIN `posts_tags` ON `posts`.id = `posts_tags`.post_id WHERE ((`posts_tags`.tag_id = 7971)) AND (((posts.trashed = 0) AND (`投稿`.`公開` = 1 AND `posts`.`clan_private` = 0)) AND ((`posts_tags`.tag_id = 7971))) ORDER BY created_at DESC LIMIT 0, 10;
空のセット (1.25 秒)
ORDER BY なし — 0.01 秒。
+----+-------------+------------+--------+-------- ----------------------------------+---------------- -------+---------+---------------------+-------+-- ------------------------+ | | ID | select_type | テーブル | タイプ | 可能な_キー | キー | key_len | 参照 | 行 | 行 エクストラ | +----+-------------+------------+--------+-------- ----------------------------------+---------------- -------+---------+---------------------+-------+-- ------------------------+ | | 1 | シンプル | 投稿タグ | インデックス | index_posts_tags_on_post_id_and_tag_id | index_posts_tags_... | 10 | ヌル | 23988 | where を使用します。インデックスの使用 | | | 1 | シンプル | 投稿 | eq_ref | PRIMARY,index_posts_on_trashed_and_crea | プライマリ | 4 | .posts_tags.post_id | 1 | where | の使用 +----+-------------+------------+--------+-------- ----------------------------------+---------------- -------+---------+---------------------+-------+-- ------------------------+
解決
- 「ORDER BY posts_tags.created_at DESC」に更新されたクエリ (アプリ コードの 2 つの小さな変更)
- インデックスが追加されました: index_posts_tags_on_created_at.
それで全部です!