DocumentDBでマルチバイト検索を実現する場合の留意事項について

Amazon DocumentDBは使っていますか?

Amazon DocumentDBはMongoDBの互換のドキュメント指向データベースであり、サービスの概要がわかるBlackBeltの資料は2019年のものが最新となっている。

MongoDBの互換となっているもののサポートされている MongoDB API、オペレーション、およびデータ型を見ると様々な面で機能差異があることがわかる。

特にマルチバイトを取り扱い場合においてはcollationに対応していないなどの問題があるため、検索要件が一致しているかどうかを検討する必要がある。

私が検証した中で、ドキュメントに記載がされていない部分において、マルチバイト検索においてインデックス適切に利用されず検索性能が大幅に低下する問題に遭遇したので、回避方法ともに紹介する。

今回の検証は、DocumentDB 4.0で行っているが、5.0でも事象が変わらない。

key に対して単一キーのインデックスを事前に作成する

rs0 [direct: primary] db1> db.col.createIndex({scope:1, key: 1})
scope_1_key_1
Enter fullscreen mode
Exit fullscreen mode

その上で、半角文字で開始するコレクションを検索すると4133レコードの結果がある場合でも134 msと高速に応答する。

rs0:PRIMARY> db.col.find({ scope:"xxxxx", key: /^A/ }).hint({scope:1,key:1}).explain("executionStats");
{ "queryPlanner" : { "plannerVersion" : 1, "namespace" : "db1.col", "winningPlan" : { "stage" : "SUBSCAN", "inputStage" : { "stage" : "SORT", "sortPattern" : { "key" : 1, "scope" : 1 }, "inputStage" : { "stage" : "FETCH", "inputStage" : { "stage" : "IXOR", "inputStages" : [ { "stage" : "IXSCAN", "indexName" : "scope_1_key_1" }, { "stage" : "IXSCAN", "indexName" : "scope_1_key_1" } ] } } } } }, "executionStats" : { "executionSuccess" : true, "executionTimeMillis" : "134.866", "planningTimeMillis" : "0.632", "executionStages" : { "stage" : "SUBSCAN", "nReturned" : "4133", "executionTimeMillisEstimate" : "133.853", "inputStage" : { "stage" : "SORT", "nReturned" : "4133", "executionTimeMillisEstimate" : "132.697", "sortPattern" : { "key" : 1, "scope" : 1 }, "inputStage" : { "stage" : "FETCH", "nReturned" : "4133", "executionTimeMillisEstimate" : "105.506", "inputStage" : { "stage" : "IXOR", "nReturned" : "0", "executionTimeMillisEstimate" : "34.238", "inputStages" : [ { "stage" : "IXSCAN", "nReturned" : "4133", "executionTimeMillisEstimate" : "33.333", "indexName" : "scope_1_key_1" }, { "stage" : "IXSCAN", "nReturned" : "0", "executionTimeMillisEstimate" : "0.902", "indexName" : "scope_1_key_1" } ] } } } } }, "serverInfo" : { "host" : "xxxxxxx", "port" : 27017, "version" : "4.0.0" }, "ok" : 1, "operationTime" : Timestamp(1703472746, 1)
}
Enter fullscreen mode
Exit fullscreen mode

しかしながら、全角文字で開始するコレクションの検索を行った場合、先ほどの条件に対して2.72倍の11266レコードの結果がある場合に、応答時間が153倍の 20518 msもかかる。

rs0:PRIMARY> db.col.find({ scope:"xxxxx", key: /^あ/ }).hint({scope:1,key:1}).explain("executionStats");
{ "queryPlanner" : { "plannerVersion" : 1, "namespace" : "db1.col", "winningPlan" : { "stage" : "SUBSCAN", "inputStage" : { "stage" : "IXSCAN", "indexName" : "scope_1_key_1", "direction" : "forward" } } }, "executionStats" : { "executionSuccess" : true, "executionTimeMillis" : "20518.276", "planningTimeMillis" : "0.303", "executionStages" : { "stage" : "SUBSCAN", "nReturned" : "11266", "executionTimeMillisEstimate" : "20517.382", "inputStage" : { "stage" : "IXSCAN", "nReturned" : "11266", "executionTimeMillisEstimate" : "20514.086", "indexName" : "scope_1_key_1", "direction" : "forward" } } }, "serverInfo" : { "host" : "xxxxxxx", "port" : 27017, "version" : "4.0.0" }, "ok" : 1, "operationTime" : Timestamp(1703472782, 1)
}
Enter fullscreen mode
Exit fullscreen mode

対応方法としては、正規表現を利用せずに文字コード範囲の検索によって実現することで応答時間を早めることができる。

db.col.find({ scope:”xxxxx”, key: {$gte: “あ”, $lt: String.fromCharCode(“あ”.charCodeAt(0)+1) } })

rs0:PRIMARY> db.col.find({ scope:"xxxxx", key: {$gte: "あ", $lt: "ぃ"}}).hint({scope:1,key:1}).explain("executionStats");
{ "queryPlanner" : { "plannerVersion" : 1, "namespace" : "db1.col", "winningPlan" : { "stage" : "SUBSCAN", "inputStage" : { "stage" : "IXSCAN", "indexName" : "scope_1_key_1", "direction" : "forward" } } }, "executionStats" : { "executionSuccess" : true, "executionTimeMillis" : "367.233", "planningTimeMillis" : "0.499", "executionStages" : { "stage" : "SUBSCAN", "nReturned" : "11266", "executionTimeMillisEstimate" : "366.099", "inputStage" : { "stage" : "IXSCAN", "nReturned" : "11266", "executionTimeMillisEstimate" : "362.641", "indexName" : "scope_1_key_1", "direction" : "forward" } } }, "serverInfo" : { "host" : "xxxxxxx", "port" : 27017, "version" : "4.0.0" }, "ok" : 1, "operationTime" : Timestamp(1703472821, 1)
}
Enter fullscreen mode
Exit fullscreen mode

Discover more from Coursity

Subscribe to get the latest posts sent to your email.

Leave a Comment

Your email address will not be published. Required fields are marked *

Discover more from Coursity

Subscribe now to keep reading and get access to the full archive.

Continue reading

Scroll to Top
Freecodecamp is another popular resource for learning web development. 311 west monroe street. Implementing these strategies, you can ensure that your membership website thrives in 2023.