3

ユースケースは次のとおりです。

利用できる、または利用できない固有のコードがたくさんあるテーブルがあります。トランザクションの一部として、テーブルから使用できるコードを選択し、後でトランザクションの後半でその行を更新したいと思います。これは同時に多くのセッションで同時に発生する可能性があるため、理想的にはランダムレコードを選択し、テーブルで行レベルのロックを使用して、から行を選択するクエリによって他のトランザクションがブロックされないようにします。テーブル。

ストレージエンジンにInnoDBを使用していますが、クエリは次のようになります。

select * from tbl_codes where available = 1 order by rand() limit 1 for update

ただし、テーブルから1行だけをロックするのではなく、テーブル全体をロックすることになります。このクエリがテーブル全体ではなく行だけをロックするようにする方法について、誰かが私にいくつかのポインタを教えてもらえますか?

アップデート

補遺:rand()を実行するのではなく、selectで明示的なキーを指定することで、行レベルのロックを実現できました。私のクエリが次のようになったら:

クエリ1:

   select * from tbl_codes where available = 1 and id=5 limit 1 for update

クエリ2:

   select * from tbl_codes where available = 1 and id=10 limit 1 for update

ただし、それは実際には問題の解決には役立ちません。

補遺2:私が行った最終的な解決策

rand()にMySQLでいくつかの問題があることを考えると、私が選択した戦略は次のとおりです。

  1. 利用可能な場合は50個のコードID=1を選択し、アプリケーション層で配列をシャッフルして、順序にランダム性のレベルを追加します。

    利用可能な場合はtbl_codesからIDを選択=1制限50

  2. ロック付きの配列を選択できるようになるまで、シャッフルされた配列からループでコードをポップし始めます

    select * from tbl_codes where available = 1 and id =:id

4

2 に答える 2

3

このクエリがMySQLによって実際にどのように実行されるかを確認すると便利な場合があります。

select * from tbl_codes where available = 1 order by rand() limit 1 for update

これにより、条件に一致するすべての行が読み取られて並べ替えられ、各行の仮想列をWHERE使用してランダムな数値が生成さrand()れ、その仮想列に基づいて(一時テーブル内の)すべての行が並べ替えられ、並べ替えられた行からクライアントに行が返されます。に達するまで設定しますLIMIT(この場合は1つだけ)。FOR UPDATE実行中にステートメント全体によって実行されるロックに影響します。そのため、句は、行がクライアントに返されるときではなく、InnoDB内で読み取られるときに適用さます

上記の明らかなパフォーマンスへの影響は別として(それはひどいです)、それから合理的なロック動作を得ることが決してありません。

短い答え:

  1. その行の値RAND()を見つけるために、または他の好きな戦略を使用して、必要な行を選択します。PRIMARY KEY例えば:SELECT id FROM tbl_codes WHERE available = 1 ORDER BY rand() LIMIT 1
  2. 必要な行のみを使用してロックしますPRIMARY KEY。例えば:SELECT * FROM tbl_codes WHERE id = N

うまくいけば、それがお役に立てば幸いです。

于 2013-01-07T21:27:39.333 に答える
1

あなたの質問に正確にマッピングされていなくても、問題はここでいくらか議論されています:http: //akinas.com/pages/en/blog/mysql_random_row/

この方法の問題は、非常に遅いことです。非常に遅い理由は、MySQLがすべての結果行を含む一時テーブルを作成し、それぞれにランダムな並べ替えインデックスを割り当てるためです。次に、結果がソートされて返されます。

この記事ではロックについては扱っていません。ただし、MySQLはすべての行をロックしavailable = 1、トランザクションが終了するまでそれらを解放しない可能性があります。

その記事はいくつかの解決策を提案していますが、残念ながら非常にハッキーであり、私がその正しさを調べなかったものを除いて、それらのどれもあなたにとって良いようには見えません。

SELECT * FROM tableWHERE id> =(SELECT FLOOR(MAX(id)* RAND())FROM table)ORDER BY id LIMIT 1;

私はMySQL内部をコマンドしないので、これは私があなたのためにできる最善のことです。また、記事はかなり古いです。

于 2013-01-07T21:05:34.160 に答える