MongdbのアップサートでのE11000重複キーエラーのエラー分析



Error Analysis E11000 Duplicate Key Errors Mongdbs Upsert



昨日のオンラインシステムで、今日ログを確認したところ、E11000の重複キーエラーエラーログがたくさん見つかりました。アップサートが使用されたため、これはアトミック操作であり、スレッドの同時実行によって引き起こされる問題を回避するため、当時は非常に混乱していましたが、なぜ主キーを繰り返すのでしょうか?間違い?

update( DBObject q , DBObject o , boolean upsert , boolean multi )

最初のパラメーターはクエリ条件であり、最初のパラメーターは実行されるアクションです。



私の処理ロジックは次のようになっています。コレクションには、6列の属性値に加えて、3列の結合一意インデックスがあり、4列が追加されます。

私のクエリ条件qは次のように書かれています



QueryBuilder.start('mb').is(bsc.getMb()).and('sb').is(bsc.getSb()).and('fd').is(bsc.getFd()) .and('mft').is(bsc.getMft()).and('mst').is(bsc.getMst()).and('mtt').is(bsc.getMtt()) .and('sft').is(bsc.getSft()).and('sst').is(bsc.getSst()).and('stt').is(bsc.getStt()) .get()

Mb、sb、fdは、ジョイント固有のインデックスです。

実行する操作は次のとおりです。

QueryBuilder.start('$inc').is(QueryBuilder.start('mc0').is(bsc.getMc0()).and('mc1').is(bsc.getMc1()) .and('sc0').is(bsc.getSc0()).and('sc1').is(bsc.getSc1()).get()) .get()

試験中は全く問題ありませんでした。



しかし、なぜ重複キーエラーがあるのですか?

アップサートの原則は、最初にqに従ってクエリを実行し、結果がない場合は最初に挿入し、結果がある場合はoに従って更新することです。

したがって、考えられる唯一の問題は、6つの属性列です。これらは一意のインデックス列ではありませんが、クエリ条件に表示されるため、インデックス列の値は同じになりますが、属性列の値は同じため、Mongodbが挿入を実行します。現在の値と同じ一意のインデックスを持つレコードがライブラリにすでに存在するため、重複キーエラーが発生します。属性列の値はインデックス付き列の値に関連付けられていますが、計算時に正しくない可能性があり、属性列の値が誤った結果を取得する可能性があります。

同時に、Mongodbの公式ウェブサイトjirahttps://jira.mongodb.org/browse/SERVER-5928でもこの問題に関する議論があります。

// Insert test document > db.test.insert({_id:1, version:2, data:3}) // Get current document > var doc = db.test.findOne({_id:1}) > printjson(doc) { '_id' : 1, 'version' : 2, 'data' : 3 } // Perform some updates on doc.data ... // Update > db.test.update({_id:1, version:doc.version},{$set:{data:doc.data}, $inc:{version:1}}, true)db.getLastError() // Update succeeded null // Try once more > db.test.update({_id:1, version:doc.version},{$set:{data:doc.data}, $inc:{version:1}}, true) // Failed with 'non-unique key' since 'version' field changed E11000 duplicate key error index: d2_feed0.feed.$_id_ dup key: { : 1 }

最後から2番目の行に注意してください

Failed with 'non-unique key' since 'version' field changed

そして私の結論は一貫しています。

後でアップサートを使用するときは、クエリ条件に一意のインデックス付き列のみを含めるようにしてください。

変更されたコード

DBObject q = QueryBuilder.start('mb').is(bsc.getMb()).and('sb').is(bsc.getSb()).and('fd').is(bsc.getFd()).get() DBObject o = QueryBuilder.start('$set') .is(QueryBuilder.start('mft').is(bsc.getMft()).and('mst').is(bsc.getMst()).and('mtt').is(bsc.getMtt()) .and('sft').is(bsc.getSft()).and('sst').is(bsc.getSst()).and('stt').is(bsc.getStt()) .get()) .and('$inc').is(QueryBuilder.start('mc0').is(bsc.getMc0()).and('mc1').is(bsc.getMc1()) .and('sc0').is(bsc.getSc0()).and('sc1').is(bsc.getSc1()).get()) .get()

setを使用して、考えられる不整合を解決します。