2016-12-30 15 views
1

現在、私たちはチケット管理システムを持っており、すべての発券システムと同様に、ラウンドロビン方式でケースに代理店を割り当てる必要があります。また、同時に、エージェントは独自のフィルタリングロジックを適用し、キューで作業することができます。MySql Logic Optimization

問題は、チケットと

  1. テーブルは現在、非常に大規模で、1000万人以上の行にまたがっています。
  2. 2人の異なるユーザーに1つのチケットを割り当てないでください。
  3. 上記の問題を解決するには、これは我々が持っている流れで、
  4. 選択クエリフィルタ条件で焼成し、上記のクエリによって返された行は、その後、IDに基づいて選択し、ためにロックされている0,1
  5. を制限しています更新。
  6. 最後に、ユーザーXがそのケースを選択したという更新情報を送信します。
  7. ステップ3が実行されている間に、他のユーザーが同じケースでロックを取得できないため、次の使用可能なケースを取得するためにクエリが複数回発生する可能性があります。
  8. 手順4でこの時間が増加するにつれて、ユーザーは増加します。

手順4でクエリで更新を選択してみましたが、クエリ全体が遅くなりました。これは、選択クエリ内に膨大な数の行があるためです。

質問、

  • 我々は完全に取る必要がある別のアプローチはありますか?
  • ストアドプロシージャで選択と更新を行うと、select for updateを実行してから更新するのと同じ結果が得られますか?

P.S - 私は同じ質問stackexchangeを求めました。

+0

行をロックする必要があります。 SELECTを使用して行を読み込み、古いユーザーを取得し、UPDATEに条件WHERE ... AND user = old_userを追加しました。そうすれば、ある行を更新すれば他のプロセスがこのチケットを取得します –

答えて

0

問題は、チケットを複数の人に割り当てることができないように、MySQLレベルのロックを使用しようとしていることです。この方法では、チケットがユーザーによってロックされているかどうかを検出する方法はありません。

2つのロック関連フィールドをチケットテーブルに追加することで、アプリケーションレベルのロックを実装します。ロックが適用されたタイムスタンプと、どのユーザーがロックを保持しているかを示すユーザーIDフィールド。ロック関連フィールドは別のテーブルに保持されてもよい(例えば、この目的のためにショッピングカートを使用することができる)。

ユーザーがチケットを選択した場合、その後、あなたは条件付きUPDATE文でこれらのロック・フィールドを更新しよう:...の代わりに

update tickets 
set lock_time=now(), lock_user=... 
where ticket_id=... and lock_time is null 

値は、アプリケーションによって供給されています。 lock_time is null基準は、チケットがすでに別のユーザーによって選択されている場合、後のユーザーがロックを無効にしないようにするためです。更新ステートメントの後に影響を受けた行の数をチェックします。それが1の場合、現在のユーザーはロックを取得しました。値が0の場合、他の誰かがチケットをロックします。

ロックデータが別のテーブルにある場合は、そのテーブルのチケットIDフィールドに一意の制限を設定し、insertを使用してロックを取得します。挿入が成功すると、ロックが獲得されます。失敗した場合、別のユーザーがチケットをロックしています。

ロックは、通常、アプリケーションがロックを解除する必要がある(ロックフィールドをnullに設定するか、または他のテーブルからロックレコードを削除する)必要があります。