3

これは私の以前の質問のフォローアップです (この投稿で問題を説明しているのでスキップできます):
MySQL InnoDB SELECT...LIMIT 1 FOR UPDATE Vs UPDATE ... LIMIT 1

環境:

  • Glassfish 上の JSF 2.1
  • JPA 2.0 EclipseLink および JTA
  • MySQL 5.5 InnoDB エンジン

私はテーブルを持っています:

CREATE TABLE v_ext (
  v_id INT NOT NULL AUTO_INCREMENT,
  product_id INT NOT NULL,
  code VARCHAR(20),
  username VARCHAR(30),
  PRIMARY KEY (v_id)
) ENGINE=InnoDB DEFAULT CHARSET=UTF8;

次のような 20,000 件のレコードが入力されます (product_idすべてのレコードで 54 件、codeランダムに生成され、一意であり、ユーザー名が NULL に設定されています)。

v_id     product_id    code                  username
-----------------------------------------------------
1        54            '20 alphanumerical'   NULL
...
20,000   54            '20 alphanumerical'   NULL

ユーザーが製品 54 を購入すると、そのテーブルからコードを取得します。ユーザーが複数回購入すると、毎回コードを取得します (ユーザー名に一意の制約はありません)。私は高活動の準備をしているので、次のことを確認したいと思います。

  • 同時実行/デッドロックが発生しない
  • パフォーマンスは、必要となるロック メカニズムの影響を受けません。

SO の質問 (上記のリンクを参照) から、このようなクエリを実行する方が高速であることがわかりました。

START TRANSACTION;
SELECT v_id FROM v_ext WHERE username IS NULL LIMIT 1 FOR UPDATE;
// Use result for next query
UPDATE v_ext SET username=xxx WHERE v_id=...;
COMMIT;

usernameただし、列にインデックスを使用する場合にのみ、デッドロックの問題が見つかりました。インデックスを追加すると少し高速化できると思いましたが、約 19,970 レコードの後でデッドロックが発生します (実際には、この行数ではかなり一貫しています)。これには理由がありますか?理解できない。ありがとうございました。

4

2 に答える 2

1

まず、テーブルの定義が間違っています。テーブルに tid 列がないため、主キーが v_id であると思われます。
次に、更新を選択すると、行がロックされます。最初のトランザクションが完了するまで他の select が来ると、行がクリアされるまで待機します。これは、まったく同じレコードにヒットするためです。したがって、この行を待つ必要があります。
ただし、これがあなたのケースで本当に深刻な問題になる可能性はほとんどありません。まず第一に、そこにユーザー名があり、第二にそこに製品 ID があるからです。最初にヒットしたのとまったく同じレコードに多くのヒットがあることはほとんどありません。ヒットしたとしても、トランザクションは非常に高速に実行されるはずです。
トランザクションを使用すると、通常、一貫したデータの同時実行性をほとんどあきらめることを理解する必要があります。データの一貫性と並行性を同時にサポートする方法はありません。

于 2012-12-27T14:56:35.830 に答える