このプロシージャは、このターゲット アプリケーションで最も頻繁にアクセスされます。同時操作を想定すると、t.value は常に変化します。
-- Table is MySQL InnoDB
-- let's call this MainSelect
SELECT t.Id
FROM table t
WHERE t.A = conditionA AND t.B = conditionB AND t.value > 0
ORDER BY RAND()
LIMIT 1 INTO vIndex FOR UPDATE;
-- IF vIndex THEN
UPDATE table SET value = value - 1 WHERE id = vIndex
目標は、このクエリを変更して、このランダムな行選択方法の形式を使用して高速化することです。完全を期すためにここに。これがこの投稿の主な質問です。
SELECT name
FROM random AS r1 JOIN
(SELECT (RAND() *
(SELECT MAX(id)
FROM random)) AS id)
AS r2
WHERE r1.id >= r2.id
ORDER BY r1.id ASC
LIMIT 1
討論:
MainSelect の行の合計数はどのように決定されますか?
これに対する答えが MainSelect サブクエリを作成し、FOR UPDATE を最も外側のクエリに移動することである場合、外側の SELECT が FOR UPDATE で行をロックする前に、ランダムに選択された行の t.value が 0 になる可能性があります。何かのようなもの:
SELECT * FROM (firstquery) s ...random selection logic.. FOR UPDATE;
この考察が正しければ、どの取引レベルを最初に設定すべきかという問題が生じます。
ありがとう
編集- 作業中のメモ:
カウントが不明なため、http://en.wikipedia.org/wiki/Reservoir_samplingかもしれません。結果としてスループットが低下することが予想されるため、高い分離レベルは避けたいと思います。
おそらく、乱数を計算するのではなく、格納して索引付けすることができます。次に、乱数が選択されます。 limit documentationによると、乱数をランダムに選択するのは非常に高速です。これに関する問題は、結果セットが均一にならないことです。
ORDER BY で LIMIT row_count を使用する場合、MySQL は、結果全体をソートするのではなく、ソートされた結果の最初の row_count 行が見つかるとすぐにソートを終了します。インデックスを使用して順序付けを行う場合、これは非常に高速です。