Trzeba też przemyśleć sprawę tego, w jaki dokładnie sposób będziemy łączyć dwie listy kroków agregacji spójnikami and
lub or
.
O ile w przypadku and
możemy po prostu skleić dwie tablice i dowolnie mieszać kroki $match
i $lookup
, o tyle w przypadku or
nie jest już tak fajnie, gdyż nie możemy korzystać z faktu, że gdy jedna z łączonych or
em strategii dostępu odrzuci zasób, nie musimy już go sprawdzać drugą z łączonych strategii dostępu.
I tutaj ponownie przydaje nam się trochę wiedzy z uczelni Istnieje sposób na rozbicie dużej alternatywy (OR) na kilka mniejszych klauzul, które można połączyć spójnikiem AND, przy 100% zachowaniu ich wartości logicznej. Możemy skorzystać z Koniunkcyjnej Postaci Normalnej:
Dzięki temu zmieniamy alternatywę (gdzie głównym operatorem jest OR) na koniunkcję (gdzie głównym operatorem jest AND) i możemy wtedy dowolnie zmieniać kolejność kolejnych kroków agregacji. Przykładowo: z wyrażenia, które jest jednym wielkim krokiem agregacji:
or(and(a,b), and(c,d))
możemy zrobić tożsame wyrażenie w postaci koniunkcyjnej:
and(or(and(a,b), c), or(and(a,b), d))
O ile taki zapis jest trochę redundantny (jest trochę powtórzeń), to głównym operatorem jest już and
- dzięki temu możemy doklejać śmiało inne klauzule, zmieniać ich kolejność i dalej optymalizować zapytanie.
O ile tego typu optymalizacja jest jak najbardziej w naszym zasięgu, o tyle z uwagi na czas póki co dla strategii dostępu or
zrobiłbym następujący algorytm:
- wszystkie lookupy na początek agregacji;
- wszystkie matche sklejone
$or
-em tuż po nich.