0

このプロシージャは、このターゲット アプリケーションで最も頻繁にアクセスされます。同時操作を想定すると、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;

この考察が正しければ、どの取引レベルを最初に設定すべきかという問題が生じます。

ありがとう

編集- 作業中のメモ:

  1. カウントが不明なため、http://en.wikipedia.org/wiki/Reservoir_samplingかもしれません。結果としてスループットが低下することが予想されるため、高い分離レベルは避けたいと思います。

  2. おそらく、乱数を計算するのではなく、格納して索引付けすることができます。次に、乱数が選択されます。 limit documentationによると、乱数をランダムに選択するのは非常に高速です。これに関する問題は、結果セットが均一にならないことです。

ORDER BY で LIMIT row_count を使用する場合、MySQL は、結果全体をソートするのではなく、ソートされた結果の最初の row_count 行が見つかるとすぐにソートを終了します。インデックスを使用して順序付けを行う場合、これは非常に高速です。

4

0 に答える 0