2012-12-26 27 views
10

私はInnoDBエンジンでのMySQLのテーブルv_extを持っている:
- ID:主キー
- コード:コードの事前生成されたリスト(ランダムに1000個のコードが生成されるとします)
- user_id:最初はNULLMySQLのInnoDBのSELECT ... LIMIT 1 ... LIMIT 1

ユーザーがアイテムを購入すると、コードを受け取ります。私はuser_id列を移入するためにテーブルを更新する必要があります。私は、同時に購入する数千のユーザーを持っている場合

START TRANSACTION; 
SELECT id FROM v_ext WHERE user_id IS NULL LIMIT 1 FOR UPDATE; -- return id 54 for ex. 
UPDATE v_ext SET user_id=xxx WHERE id=54; 
COMMIT; 

または

UPDATE v_ext SET user_id=xxx WHERE user_id IS NULL LIMIT 1; 

目のオプションは安全です:私は2つの選択肢がありますか?その場合、この2番目のオプションは1つのクエリしか必要ないため、パフォーマンスが向上すると想定するのは正しいですか?

+0

'user_id'に' UNIQUE'制約がありますか? (つまり、ユーザーは1つのコードしか持てませんか?) – eggyal

+0

'EXISTS'は並行性とパフォーマンスの面でより優れた使い方です。 – bonCodigo

+0

UNIQUEは制約ではありません。user_idは、商品を購入するのと同じくらい多くのコードを取得できます。 – JScoobyCed

答えて

10

回答が得られなかったので、私はベンチマークを始めました。次のように私の基準は以下のとおりです。

  • 2万事前に生成されたコード
  • 2万要求、100並行処理でのApache abコマンドの使用:ab -n 20000 -c 100
  • サーブレット - > EJB(JPA 2.0 EclipseLinkは、JTA)を実行します
  • 2つのバージョンのサーブレット、1つはオプション(SELECT ... FOR UPDATE)、もう1つはオプション2(UPDATE ... LIMIT 1)の2つのバージョン(DB内の実際の状況でのJSFアクション) )
  • 停止したグラスフィッシュは、手作業でサーブレットを5回押して暖めてください
  • テスト3回ずつ実行され、平均が

結果提供されUSER_IDするNULLにすべてをリセットし、アップ:

SELECT ... FOR UPDATEを。 UPDATE ...:

Concurrency Level:  100 
Time taken for tests: 758.116 seconds 
Complete requests:  20000 
Failed requests:  0 
Write errors:   0 
Row updated:   20000 

UPDATE .... LIMIT 1:

Concurrency Level:  100 
Time taken for tests: 773.659 seconds 
Complete requests:  20000 
Failed requests:  0 
Write errors:   0 
Row updated:   20000 

だから、少なくとも私のシステム上、2つのクエリを持つオプションは、1つのクエリよりも効率的と思われます。私はそれを期待していませんでした:)

+0

+1興味深い発見。並行処理の問題が発生しましたか? –

+0

私は見ることができません。私は2万回の成功したリクエストで20,000行を更新しました。 – JScoobyCed

+0

デッドロックの発生は、user_idを実際にvarchar列にインデックス付けする場合にのみ発生します)http://stackoverflow.com/questions/14052038/mysql-select-for-update-with-index-has-concurrency-issue – JScoobyCed

関連する問題