MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

MongoDB Regex, Index und Leistung

MongoDB unterstützt reguläre Ausdrücke mit dem $regex-Operator. Diese MongoDB-Regex-Abfragen haben jedoch einen Nachteil:Alle bis auf einen Regex-Typ nutzen Indexe schlecht aus und führen zu Leistungsproblemen. Bei einem Produktionsserver mit großen Datenmengen kann eine schlechte Regex-Abfrage Ihren Server in die Knie zwingen.

Regex-basierte MongoDB-Abfragen sind eine ziemlich häufige Abfrage in den meisten Anwendungen, die MongoDB verwenden. Dies ähnelt der Operation „LIKE“, die von den meisten relationalen Datenbanken unterstützt wird. Die Syntax des Befehls lautet wie folgt

{ $regex: /pattern/, $options: '<options>' }
E.g. { name: { $regex: /^acme.*test/}}

Ausführlichere Informationen zur Regex-Operation und zusätzliche Optionen finden Sie in der MongoDB-Dokumentation

Für den Rest dieser Diskussion gehen wir davon aus, dass das Feld, mit dem Sie übereinstimmen, einen Index hat. Wenn Sie nicht indizieren, führt dies zu einem Sammlungsscan und einer sehr schlechten Leistung. Auch wenn das Feld indiziert ist, kann dies jedoch zu einer schlechten Leistung führen. Der Grund dafür ist, dass MongoDB Indizes nur dann sinnvoll nutzen kann, wenn Ihr regulärer Ausdruck ein „Präfixausdruck“ ist – das sind Ausdrücke, die mit dem Zeichen „^“ beginnen.

Z.B. { name: { $regex: /^acme/}}

Dadurch kann MongoDB eine Reihe von Indexeinträgen identifizieren, die für diese Abfrage relevant sind, und führt zu effizienten Abfragen. Jede andere Abfrage führt zu einem Indexscan, da MongoDB den Scan nicht auf eine Reihe von Indexeinträgen einschränken kann. Ein Index-Scan ist besonders schlecht, da alle Indizes in den Speicher ausgelagert werden müssen und dies den Arbeitssatz Ihres Servers beeinträchtigt (Tatsächlich könnte der Index-Scan zu einer schlechteren Leistung führen als ein Sammlungs-Scan – er führt zu doppelt so vielen Seitenfehlern ).

Sehen wir uns einige Beispiele und die daraus resultierenden Abfragepläne an. Für unsere Testzwecke habe ich eine Sammlung mit 100.000 Dokumenten angelegt. Jedes Dokument hat ein firstName-Feld, das eine 16-stellige Zeichenfolge ist.

Beispiel 1: { name:{ $regex:/^acme/}}
Ergebnis:Effiziente Indexnutzung
Abfrageplan:

executionStats" : {
       "executionSuccess" : true,
       "nReturned" : 0,
       "executionTimeMillis" : 0,
       "totalKeysExamined" : 1,
       "totalDocsExamined" : 0,

Beispiel 2: { name:{ $regex:/^acme/i}}
Ergebnis:Ineffizienter Index-Scan aufgrund der Anforderung, dass die Groß-/Kleinschreibung nicht beachtet wird. Im Grunde negiert die Option /i also den „Präfixausdruck“
Abfrageplan:

        "executionStats" : {
                "executionSuccess" : true,
                "nReturned" : 0,
                "executionTimeMillis" : 137,
                "totalKeysExamined" : 100000,
                "totalDocsExamined" : 0,

Beispiel 3: { name:{ $regex:/acme.*corp/}}
Ergebnis:Ineffizienter Index-Scan
Abfrageplan:

                "executionSuccess" : true,
                "nReturned" : 0,
                "executionTimeMillis" : 167,
                "totalKeysExamined" : 100000,
                "totalDocsExamined" : 0,

Beispiel 4: { name:{ $regex:/acme/}}
Ergebnis:Ineffizienter Index-Scan

        "executionStats" : {
                "executionSuccess" : true,
                "nReturned" : 0,
                "executionTimeMillis" : 130,
                "totalKeysExamined" : 100000,
                "totalDocsExamined" : 0,