1

対称的なユーザー関係のテーブルがあります:

CREATE TABLE IF NOT EXISTS `friends` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_a` int(11) NOT NULL DEFAULT '0',
  `user_b` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

この表には次の情報が含まれています。

  • IDが1のユーザーはIDが2のユーザーの友達です
  • IDが3のユーザーはIDが1のユーザーの友達です

は、次のように結論付けています。

  • ID 1 のユーザーには 2 人の友達 (ID 3 と ID 2) がいます
  • ユーザーの ID は 2 つの列のいずれかになります(ユーザー ID 1 を参照)。

ユーザー 1 がユーザー 3 と友達であるかどうかを確認する効率的なクエリを作成するにはどうすればよいですか?

なぜ私は効率的な方法について尋ねているのですか?まあ、私には 3 つの異なるソリューションがあるため (さらに多くのソリューションがある可能性があります)、それらすべての中で最も効率的なものを選択するのに苦労しています。何か助けはありますか?

アプローチ 1:

SELECT user_b AS user_a
FROM    friends
WHERE   (user_a = :user_a AND user_b = :user_b)
UNION ALL
SELECT  user_a
FROM    friends
WHERE   (user_b = :user_b AND user_a = :user_a)

アプローチ 2:

SELECT * FROM friends WHERE (user_a = :user_a AND user_b = :user_b) OR
(user_b = :user_a AND user_a = :user_b)

アプローチ 3:

SELECT user_a FROM (
SELECT user_b AS user_a
FROM    friends
WHERE   user_a = :user_a
UNION ALL
SELECT  user_a
FROM    friends
WHERE   user_b = :user_a
) AS newtab WHERE newtab.user_a = :user_b;

PHP チェック:

$my_id = 1;
$friend_id = 3;
$stmt = $dbh->prepare("SELECT ..."); // approach 1 or 2 or 3 or ...
$stmt->bindParam(':user_a', $my_id, PDO::PARAM_STR);
$stmt->bindParam(':user_b', $friend_id, PDO::PARAM_STR);
$stmt->execute();

if ($stmt->rowCount() > 0) {
echo "You are friends";}
else { echo "he is not your friend";}

パフォーマンスに関して - どちらのアプローチが優れていますか?

編集:

テスト:

$start_2 = microtime(true);
for ($i = 1; $i <= 100; $i++) {
    $stmt->execute();
}
$end_2 = microtime(true);

結果

1 : 0.14095306396484

2 : 0.063449859619141

3 : 0.18946194648743

4

2 に答える 2

1

テストで既にわかっているように、アプローチ 2 の方が高速です。

この理由についての私の見解は、ケースの 50% では、最初の部分でその部分を満たすのに十分でWHEREあり、2 番目の部分はまったく実行されないということです。

常に user_a < user_b である @Luis のアイデアを追加すると、これらの 50% は 100% になります。

また、結合とサブクエリには一時テーブルが必要な場合があり、場合によってはディスク上にある必要さえあります。これは非常に遅いため、避ける必要があります。

クエリが一時テーブルの実行を使用しているかどうかをテストするには、extraセクションでusing temporaryEXPLAINを探します。

また、その余分な ID (役に立たないデータ) を取り除き、user_a、user_b を主キーとして配置します。これにより、高速なインデックスが得られます (user_a < user_b であることがわかっている場合)。

于 2013-03-04T19:01:56.203 に答える
1

ユーザー ID のインデックスを作成し、追加の ID が本当に必要かどうかを確認する必要があります。

簡単にするためにオプション2を使用しますが、それが最も効率的な方法であるかどうかはわかりません。魔女の方が簡単で高速であることをテストできます。

選択クエリが挿入よりもはるかに一般的で、多くのレコードがあった場合、これと同様のことを一度行う必要があったため、常に特定の順序で挿入しました。この場合、user_a < user_b 、したがって、クエリで片側のみを確認できます。

于 2013-03-04T18:47:41.000 に答える