0

私が現在開発しているシステムは、MongoDB 2.4.4 を使用しています

私はユーザーのコレクションを持っています。

複合インデックスがあり{ "LASTNAME" : 1 , "FIRSTNAME" : 1 , "EMAIL" : 1 , "CITY" : 1 , "STATUS" : 1} ます。パフォーマンスの向上なしに、単一のインデックスでも試しました

システムには 400.000 件のテスト レコードが含まれています。

クエリ (org.springframework.data.mongodb.core.query.Query からの Java デバッグ):

{ "LASTNAME" : { "$regex" : "^Schm"}},
  Fields: { "FIRSTNAME" : 1 , "EMAIL" : 1 , "CITY" : 1 , "STATUS" : 1 ,"LASTNAME" : 1},
  Sort: { "LASTNAME" : 1 , "FIRSTNAME" : 1 , "EMAIL" : 1 , "CITY" : 1 , "STATUS" : 1}

16 ミリ秒以内に実行されます。これは素晴らしいことです。

このクエリは MongoDB コンソールには表示されません (ここに投稿するデバッグ情報はありません)。

しかし、私は最初から検索するだけでなく、大文字と小文字を区別しないようにするのが好きです。

クエリ:

{ "LASTNAME" : { "$regex" : "^Schm" , "$options" : "i"}},
  Fields: { "FIRSTNAME" : 1 , "EMAIL" : 1 , "CITY" : 1 , "STATUS" : 1 , "LASTNAME" : 1},
  Sort: { "LASTNAME" : 1 , "FIRSTNAME" : 1 , "EMAIL" : 1 , "CITY" : 1 , "STATUS" : 1}

897 ミリ秒以内に実行されます。それは容認できないほど遅いです。

Mongo コンソールには次のように表示されます。

query: { query: { LASTNAME: /^Schm/i },
  orderby: { LASTNAME: 1, FIRSTNAME: 1, EMAIL: 1, CITY:1, STATUS: 1 }
} cursorid:1252405545564528 ntoreturn:25 ntoskip:0 nscanned:297651
keyUpdates:0 numYields: 1 locks(micros) r:1391715 nreturned:25 reslen:4422 897ms

ご覧のとおり。インデックスの問題を指摘するのは scanAndOrder の問題ではありません。

次に、ほとんどのシナリオ (ユーザーから挿入された小文字と大文字) に適合する次の方法で解決しようとしましたが、それも遅くなりました。私の期待は、最初のクエリと同じくらい長く実行されることでした。

クエリ:

{ "$or" : [ { "LASTNAME" : { "$regex" : "^Schm"}} , { "LASTNAME" : { "$regex" : "^schm"}} , { "LASTNAME" : { "$regex" : "^SCHM"}}]},
  Fields: { "FIRSTNAME" : 1 , "EMAIL" : 1 , "CITY" : 1 , "STATUS" : 1 , "LASTNAME" : 1},
  Sort: { "LASTNAME" : 1 , "FIRSTNAME" : 1 , "EMAIL" : 1 , "CITY" : 1 , "STATUS" : 1}

1300ミリ秒以内に実行されます。これ以上言うことはありません。

MongoDB コンソール:

query: { query: { $or: [ { LASTNAME: /^Schm/ }, { LASTNAME: /^schm/ }, { LASTNAME: /^SCHM/ } ] },
  orderby: { LASTNAME: 1, FIRSTNAME: 1, EMAIL: 1, CITY: 1, STATUS: 1 }
} cursorid:43560166842085 ntoreturn:25 ntoskip:0 nscanned:297651
keyUpdates:0 numYields: 1 locks(micros) r:1531168 nreturned:25 reslen:4422 1300ms

では、最初の検索とほぼ同じ速度で大文字と小文字を区別せずに検索するにはどうすればよいでしょうか? 最大150ms!

4

1 に答える 1

9

大文字と小文字を区別しない機能を追加するとすぐに、インデックスを使用できなくなります。これは、検索のサポートが必要なアプリケーションを構築する際の重要な設計上の問題です。

これを克服するには、すでに小文字になっている姓を別のフィールドに保存し、大文字と小文字を区別してクエリを実行する必要があります (Mongo に渡す前に、すべての検索クエリを小文字に変換する必要があります)。

編集

2.4でテキスト検索が追加されたようです。ここでそれについて読んで、それが必要なことを行うかどうかを確認してください.

余談ですが、パフォーマンスに本当に関心がある場合 (質問から判断すると、そう思われるかもしれません)、データ ストレージ エンジンに対する検索を再検討する必要があります。ElasticSearch (または単純な Lucene インデックス) などの代替検索エンジンを使用して、検索トラフィックをプライマリ データ ストアから遠ざけることを検討してください。

于 2013-07-12T12:57:21.457 に答える