mysqlの最適化:一意の値の列から異なる値の以前に選択されていないランダムなペアを選択する

一意の(反復されない)値の列から、以前に選択された異なるランダム値のペアを選択する最も効率的な方法は何でしょうか?

私の現在のアプローチは(値のすべてのペアを既に別の "mytable_associations"テーブルに関連付けておく)

SELECT * FROM
(
 SELECT id,count(*) AS associations_count FROM mytable 
 INNER JOIN mytable_associations 
 WHERE (myvalue=myvalue1 OR myvalue=myvalue2) 
 GROUP BY myvalue 
 HAVING associations_count<(SELECT count(*) FROM mytable)-1
 ORDER BY rand() limit 1
) mytable1 
LEFT JOIN 
(SELECT myvalue AS myvalue2 FROM mytable) mytable2
ON mytable1.myvalue1<>mytable2.myvalue2
WHERE
(
 SELECT myvalue1 FROM mytable_associations 
 WHERE
 myvalue1=mytable1.myvalue1 AND myvalue2=mytable2.myvalue2
 OR
 myvalue1=mytable2.myvalue2 AND myvalue2=mytable1.myvalue1
) IS NULL;

(そして、もちろん、mytable_associationsをこの新しいアソシエーションに更新してください)

あなたが見ることができるように、最適化によって大きな利益を得ることができます。

(コード内の貧弱なインデントについては申し訳ありませんが、私は本当にどのようにmysqlコマンドをインデントするかわかりません)。

みんな助けてくれますか?

(これはこれまでのところ私の最初の質問です:確かに私は間違ったことをたくさんやっていますが、結果として起こるフレーミングを理解していますが、私にはあまり重視しないでください))

2
基本的にそれは2つの部分です:最初に私は他のものと結合されていない値を選択します。私はSELECT RANDOM FROM mytable WHERE(各値FROM associations_tableのアソシエーション数を選択)<(mytableからの選択カウント(*))-1。それが明確であれば、残りの部分はassociations_tableにまだ関連付けられていない別の値を選択しているだけです。これが最後の2つのWHERE句です。
追加された 著者 NotGaeL,
コードを混乱の少ないものにするための更新を行っただけです。今読んでほしいと思っていますが、とにかくBill Karwinのソリューションを見てみると、これは私が探していたものです
追加された 著者 NotGaeL,
あなたの質問を理解するのはちょっと難しいようです。クエリーのさまざまな部分について説明し、何をしているかなど、いくつかの洞察を伝えてください。あなたが達成したいと思っているものの模範的な例を与えることができれば素晴らしいでしょう
追加された 著者 Abhay,

1 答え

order by rand()を含むソリューションはすべて非効率的になります。代替案については、以下を参照してください。

既に選択した番号を除外するには、どうすればいいのですか(これは擬似コードです):

$c1 = SELECT COUNT(DISTINCT myvalue) FROM mytable
$c2 = SELECT COUNT(*) FROM mytable_associations

$offset = ROUND( RAND() * ($c1 * ($c1-1) - $c2) )

SELECT v.* FROM (
  SELECT LEAST(m1.myvalue,my2.myvalue) AS myvalue1,
    GREATEST(m1.myvalue,my2.myvalue) AS myvalue2
  FROM (SELECT DISTINCT myvalue FROM mytable) AS m1 
  INNER JOIN (SELECT DISTINCT myvalue FROM mytable) AS m2
    ON m1.myvalue <> m2.myvalue
) AS v
LEFT OUTER JOIN mytable_associations AS a USING (myvalue1,myvalue2)
WHERE a.myvalue1 IS NULL
LIMIT 1 OFFSET $offset

By ensuring that myvalue1 < myvalue2, and storing them in that order in mytable_associations, you can simplify the join.

2
追加された
rand()で順序を使用していないのは間違いなく改良点ですが、ポイント3については、「a.myvalue1 IS NULL」が(a、b)、(b、a)を選択する際の重複を避ける方法を見ることができません。私はそれを実行しようとすると、未知の列myvalue1と言うエラーが出ます(試したa.myvalue1とmytable_associations.myvalue1も、どちらも構文エラーに変わりました)。それを防ぐために、両方の組み合わせを関連付けテーブルに追加する必要がありますか?このエラーにつながるソリューションを実行しようとすると、何が間違っていますか?
追加された 著者 NotGaeL,
(ちょっと返事をいただき、ありがとうございます:私はSQLから始めていますが、時には適切に処理する方法を理解するのが非常に難しい場合もあります)
追加された 著者 NotGaeL,
素晴らしい!明確で効率的なソリューション。あなたは偉大だ、あなたの助けを大変ありがとう!
追加された 著者 NotGaeL,
申し訳ありませんが、私はあなたの元の質問の質問を誤解し、私はあなたのテーブル構造を誤解しました。私は自分の答えを書き直しました。
追加された 著者 Bill Karwin,