フレンド フィード クエリで奇妙な問題が発生しています。背景は次のとおりです。
私は3つのテーブルを持っています
checkin - around 13m records
users - around 250k records
friends - around 1.5m records
チェックイン テーブル - ユーザーによって実行されたアクティビティが一覧表示されます。(ここには多数のインデックスがありますが、user_id、created_at、および(user_id、created_at)にインデックスがあります。users テーブルは基本的なユーザー情報です。user_id にインデックスがあります。friends テーブルには、user_id、target_id、および is_approved があります。 (user_id, is_approved) フィールドにインデックスがあります。
私のクエリでは、任意のユーザーの基本的な友達フィードだけをプルダウンしようとしています - だから私はこれをやっています:
SELECT checkin_id, created_at
FROM checkin
WHERE (user_id IN (SELECT friend_id from friends where user_id = 1 and is_approved = 1) OR user_id = 1)
ORDER by created_at DESC
LIMIT 0, 15
クエリの目的は、すべてのユーザーのフレンドとそのアクティビティの checkin_id と created_at を取得することです。これは非常に単純なクエリですが、ユーザーの友人が最近のアクティビティを大量に持っている場合、このクエリは非常に高速です。EXPLAIN は次のとおりです。
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY checkin index user_id,user_id_2 created_at 8 NULL 15 Using where
2 DEPENDENT SUBQUERY friends eq_ref user_id,friend_id,is_approved,friend_looku... PRIMARY 8 const,func 1 Using where
説明として、user_id は user_id の単純なインデックスですが、user_id_2 は user_id と created_at のインデックスです。friends テーブルでは、friends_lookup は user_id と is_approved のインデックスです。
これは非常に単純なクエリで、get は次のように完了します。
ただし、ユーザーの友達のアクティビティが最近のものではなく、データがあまりない場合、同じクエリは約 5 ~ 7 秒かかり、前のクエリと同じ EXPLAIN になりますが、時間がかかります。
より多くの友人に影響を与えているようには見えませんが、最近のアクティビティでスピードアップしているようです.
これらのクエリを最適化して、アクティビティに関係なく同じ速度で実行されるようにするためのヒントはありますか?
サーバーのセットアップ
これは、16 GB の RAM を実行する専用の MySQL サーバーです。Ubuntu 10.10 を実行しており、MySQL のバージョンは 5.1.49 です。
アップデート
したがって、ほとんどの人は、IN 部分を削除して INNER JOIN に移動することを提案しています。
SELECT c.checkin_id, c.created_at
FROM checkin c
INNER JOIN friends f ON c.user_id = f.friend_id
WHERE f.user_id =1
AND f.is_approved =1
ORDER BY c.created_at DESC
LIMIT 0 , 15
EXPLAIN で報告されているように、このクエリは 10 倍悪いです。
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE f ref PRIMARY,user_id,friend_id,is_approved,friend_looku... friend_lookup 5 const,const 938 Using temporary; Using filesort
1 SIMPLE c ref user_id,user_id_2 user_id 4 untappd_prod.f.friend_id 71 Using where
このクエリの目的は、すべての友達のアクティビティと自分のアクティビティを同じクエリで取得することです (2 つのクエリを作成して結果をマージし、created_at で並べ替える必要はありません)。また、別のクエリの重要な部分であるため、user_id のインデックスを削除することもできません。
興味深いのは、アクティビティがあまりないユーザー アカウントでこのクエリを実行すると、次のような説明が得られることです。
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE f index_merge PRIMARY,user_id,friend_id,is_approved,friend_looku... user_id,friend_lookup 4,5 NULL 11 Using intersect(user_id,friend_lookup); Using wher...
1 SIMPLE c ref user_id,user_id_2 user_id 4 untappd_prod.f.friend_id 71 Using where
何かアドバイス?