1

前もって 2 つのこと。まず、私の問題に対する解決策があります。私はそれが良い解決策であるかどうか、そして私がそれを改善できるかどうかについてのガイダンスのためにここにいます. 第二に、私の無知を前もって謝罪したいと思います! 私はサイトを構築しているJavaの男で、SQLを始めたばかりです。私はまだやるべきことがたくさんあるので、ここでガイダンスを探しています。

このクエリを処理する 3 つのテーブルがあります。

  1. ユーザー - サイト上のすべてのユーザーに関する基本情報
  2. 友達 - 友達である 2 人のユーザー ID を保持します
  3. Strides - Strides は、Facebook のウォール ポストのようなものと考えてください。どのユーザーも、ストライドの更新を自分のウォールまたは友達のウォールに投稿できます。

すべてのユーザーの友達を見つけて ID 番号を返す SQL ステートメントは次のようになります。

SELECT user.id 
FROM user 
INNER JOIN friends ON user.id = friends.user2 WHERE friends.user1 = 1 
UNION ALL 
SELECT user.id FROM user 
INNER JOIN friends on user.id = friends.user1 WHERE friends.user2 = 1

今の私の目標は、Facebook のようなライブ フィードを持つことです。ユーザーがストライドを投稿するたびに、すべての友人に通知されるようにします。したがって、ステップ 1 は、上記で行ったすべてのユーザーの友人を取得することであることがわかりました。そこで、これらの友達をストライド テーブルにリンクさせたいと思います。

ストライド テーブルには、sourceUserId (ストライドを書いた人) と recipientId (ストライドを受け取った人) の列があります。したがって、自分のボードに書き込み、ID が 2 の場合、両方の列で 2 になります。私の目標は、すべてのユーザーの友達、およびそれらの友達が自分のボードと友達のボードで行ったすべての投稿を見つけることができる SQL ステートメントを作成することです。

あまりにも多くのグーグル検索の後、SQL サブクエリについて知り、結果を出しました。問題は、私が新人で、今日これらのことを学んだばかりなので、これが良い結果かどうかわからないことです! 私はスケーラビリティが怖いです.100人、1,000人、または100,000人のユーザーがいると、これがうまくいかない場合! だから私の質問は、

  1. ここではサブクエリが最適なオプションですか? もしそうなら、私はそれを正しくしましたか?そうでない場合、どうすればこれを修正できますか
  2. このクエリを高速化するためにインデックスを作成する必要がある列はありますか。
  3. 今後のクエリを改善する方法について、新しい SQL 担当者に何かアドバイスはありますか

これが私が思いついたコードです!

SELECT * FROM stride WHERE sourceUserId = ANY
(
    SELECT user.id 
    FROM user 
    INNER JOIN friends ON user.id = friends.user2 WHERE friends.user1 = 1 
    UNION ALL 
    SELECT user.id FROM user 
    INNER JOIN friends on user.id = friends.user1 WHERE friends.user2 = 1
) 
AND recipientId = ANY
(
    SELECT user.id 
    FROM user 
    INNER JOIN friends ON user.id = friends.user2 WHERE friends.user1 = 1 
    UNION ALL 
    SELECT user.id FROM user 
    INNER JOIN friends on user.id = friends.user1 WHERE friends.user2 = 1
) 

更新:たくさんの新しい知識により、0.0009 秒のライブ フィードの確実な SQL ステートメントを取得することができました! 興味のある方はこちらから。

SELECT stride.id AS link, sourceUser.userName, sourceUser.displayName, recipientUser.fName AS recipient, sourceUser.currentDefault, stride.content, stride.timestamp,

CASE WHEN (recipientId = sourceUserId) THEN "personalStride" ELSE "friendStride" END AS notType
FROM stride

INNER JOIN user AS sourceUser ON sourceUser.id = stride.sourceUserId
INNER JOIN user AS recipientUser ON recipientUser.id = stride.recipientId

WHERE sourceUserId = ANY
(
    SELECT CASE WHEN user1 = 1 
    THEN user2 ELSE user1 END AS sourceUserId
    FROM friends
    WHERE user1 = 1 OR user2 = 1
) 
AND recipientId = ANY
(
    SELECT CASE WHEN user1 = 1 
    THEN user2 ELSE user1 END AS sourceUserId
    FROM friends
    WHERE user1 = 1 OR user2 = 1
)
ORDER BY timestamp desc
4

1 に答える 1

0

組合は必要ありません:

SELECT 
    CASE
        WHEN f.user1=u.id 
        THEN f.user2 
        ELSE f.user1 
    END AS f_id 
FROM user 
   JOIN friends AS f 
        ON f.user1=u.id OR f.user2=u.id
WHERE u.id = 1

実際には、ユーザーと一緒に参加する必要もありません(もちろん、friendsテーブルのすべてのIDがusersテーブルで一致すると仮定します)。マジックナンバーの代わりに素敵な「u.id」を使用できるように追加しました。

SELECT 
    CASE 
        WHEN f.user1=2 
        THEN f.user2 
        ELSE f.user1 
    END AS f_id 
FROM friends AS f 
WHERE f.user1=2 OR f.user2=2

http://sqlfiddle.com/#!2/afb4d/8

編集: 他のクエリに関しては、問題はもう少し複雑です私はそのようなクエリに行き着きました:

SELECT s.id,s.sourceUserId,s.recipientId
FROM STRIDE as s 
    JOIN  friends AS f 
        ON 
          (
            ((s.sourceUserId=f.user1 OR s.recipientId=f.user1) AND f.user2=1) OR
            ((s.sourceUserId=f.user2  OR s.recipientId=f.user2)AND f.user1=1)
          )
GROUP BY s.id,s.sourceUserId,s.recipientId
HAVING COUNT(*)=2 OR s.sourceUserId=s.recipientId;

http://sqlfiddle.com/#!2/83363/1 ソースまたは受信者がユーザーの友達である場合は行を選択し、合計します。行が2回表示された場合は、ソースと受信者の両方が友達。また、source = receiveieの場合は、1回しか表示されないため、これらを選択します。

サブクエリは便利ですが、2つの異なる集計が必要でない限り、サブクエリを回避できます。通常、サブクエリを回避する方がはるかに高速です。

于 2013-03-05T01:37:27.493 に答える