「オッズ」は整数ではなく、「9」を持つものは「1」よりも 9 倍可能性が高いと推測しています。
これを行う適切な方法は、累積合計を使用することです。次に、累積合計の最小値と最大値の間のランダムな値を生成し、その範囲内にあるレコードを選択します。次のクエリは、MySQL でこれを行います。
select t.*
from (select t.*,
coalesce((select sum(odds) from t t2 where t2.id < t.id), 0) as cumsum,
const.sumodds
from t cross join
(select rand()*sum(odds) as val from t) const
) t
where val between cumsum and cumsum + t.odds
ただし、これは非等価結合を行っているため、MySQL ではおそらく法外なコストがかかります。他のデータベースには、単一のクエリで累積合計を実行する機能があります。MySQL には、これを行う効率的な方法がありません。
クエリを最適化する方法は、問題の他の特定の要因によって異なります。「オッズ」はいくつの異なる値をとりますか? 一時テーブルを使用できますか?
今は解決策を書き出す時間がありませんが、もっと効率的な方法があります。Yアイデアは、問題を 2 つの検索に分割することです。最初のものは、どの「オッズ」値が勝つかを見つけます。2番目は、どの行が勝つかを見つけます。
詳細は次のとおりです。
(1) データをオッズで表にまとめます。このテーブルには 11 行あり、それぞれの「オッズ」と「カウント」が含まれます。
(2) 最初の行の 0 から始めて、各行の「count*odds」の合計を計算します。これは非常に少量のデータであり、すぐに実行されるため、上記のクエリをガイドとして使用できます。
(3) として乱数を計算しrand()*<sum of all odds>
ます。次に、数値が cumsum と cumsum+odds の間にあるオッズを見つけます。
(4) 元のテーブルに戻り、次のようなクエリを発行します。
select *
from t
where odds = <winning odds>
order by rand()
limit 1