13

"SELECT MAX(id) AS id FROM TABLE"背景:開発者が、最後に挿入された行(auto_increment列を持つテーブル)のIDを取得する必要があるときと同じように、MYSQLクエリを実行する関数を使用しているように見えるシステムで作業しています。

私はこれが恐ろしい慣行であることを知っています(同時リクエストはレコードを台無しにするため)、そして私はそれを非技術/管理チームに伝えようとしています、彼らの応答は...

"Oh okay, we'll only face this problem when we have 
(a) a lot of users, or 
(b) it'll only happen when two people try doing something
    at _exactly_ the same time"

私はどちらの点にも同意しませんし、私たちが計画しているよりもずっと早くこの問題に遭遇すると思います。しかし、私は、混乱したリンクが表示される前に、システムを使用する必要があるユーザーの数を計算する(またはメカニズムを理解する)ことを試みています。

それに対する数学的洞察はありますか?繰り返しますが、私はその恐ろしい慣行を知っています、私はこの状況での変数を理解したいだけです...


更新:コメントの皆さんに感謝します-私たちは正しい方向に進んでおり、コードを修正しています!

4

5 に答える 5

5

重要なのは、潜在的な悪い状況が起こりそうかどうかではありません。重要なのは、それらが可能かどうかです。問題が発生する可能性が自明でない限り、それがわかっている場合は回避する必要があります。

リモートで可能なエッジケースに対処するために、1行の関数呼び出しを5000行のモンスターに変更することについて話しているわけではありません。私たちは実際に呼び出しをより読みやすく、より正しい使用法に短縮することについて話している。

@Mark Ba​​kerにはパフォーマンスに関する考慮事項があることに同意しますが、idは主キーであるため、MAXクエリは非常に高速になります。確かに、LAST_INSERT_ID()(セッション変数から読み取るだけなので)高速になりますが、ほんのわずかな量です。

そして、これが発生するために多くのユーザーを必要としません。必要なのは、多数の同時リクエストです(それほど多くはありません)。挿入の開始から選択の開始までの時間が50ミリ秒である場合(トランザクションセーフなDBエンジンを想定)、これで一貫して問題が発生し始めるのに必要なリクエストは1秒あたり20回だけです。重要なのは、エラーのウィンドウが重要であるということです。1秒あたり20リクエスト(実際にはそれほど多くはありません)と言い、平均的な人が1分あたり1ページにアクセスすると仮定すると、1200ユーザーしか話していません。そして、それはそれが定期的に起こるためです。これは、2人のユーザーで1回発生する可能性があります。

そして、このテーマに関するMySQLドキュメントから直接:

You can generate sequences without calling LAST_INSERT_ID(), but the utility of 
using the function this way is that the ID value is maintained in the server as 
the last automatically generated value. It is multi-user safe because multiple 
clients can issue the UPDATE statement and get their own sequence value with the
SELECT statement (or mysql_insert_id()), without affecting or being affected by 
other clients that generate their own sequence values.
于 2010-08-18T12:45:30.753 に答える
2

ドキュメントに記載されているように、使用する代わりにSELECT MAX(id)実行する必要があります。

代わりに、SQLクエリで内部MySQL SQL関数LAST_INSERT_ID()を使用してください

それでも、「スレッドセーフ」ではなく、競合状態になる可能性もありますSELECT MAX(id)mysql_insert_id()最善のオプションは、リクエストの前後にテーブルをロックすることです。または、トランザクションをさらに有効に活用します。

于 2010-08-18T12:08:19.017 に答える
0

私にはそのための数学はありませんが、応答(a)は少しばかげていることを指摘しておきます。会社はたくさんのユーザーを望んでいませんか?それは目標ではありませんか?その応答は、最初に1回正しく解決するのではなく、2回目に問題を解決したいということを意味します。

于 2010-08-18T12:10:34.900 に答える
0

これは、ある挿入とそのクエリの実行の間に誰かがテーブルに何かを追加したときに発生します。したがって、あなたの質問に答えるために、システムを使用している2人は、問題が発生する可能性があります。

少なくともLAST_INSERT_ID()を使用すると、特定のリソースの最後のIDが取得されるため、間に追加された新しいエントリの数は関係ありません。

于 2010-08-18T12:10:50.523 に答える
0

間違ったID値が返されるリスクに加えて、SELECT MAX(id)の追加のデータベースクエリオーバーヘッドもあり、単純なmysql_insert_id()よりも実際に実行するPHPコードが多くなります。なぜ故意に何かを遅くするようにコーディングするのですか?

于 2010-08-18T12:34:44.350 に答える