Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PERF-5374 Improve comment headers for multiplanner/ workloads #1213

Merged
merged 28 commits into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
7d3550a
PERF-5374 Improve comment headers for multiplanner/ workloads
dpercy May 7, 2024
9ac18f3
typo of -> or
dpercy May 10, 2024
727c8f5
no need to split on "classic and SBE"
dpercy May 10, 2024
3966b55
typo "prepence" -> presence
dpercy May 10, 2024
608dbb0
don't split on "choice of multiplanner"
dpercy May 10, 2024
46a82aa
collectionSize one word
dpercy May 10, 2024
d813797
Merge branch 'master' into PERF-5374-comments
dpercy May 10, 2024
bb2a774
state explicitly ClusteredCollection doesn't do a clustered scan
dpercy May 10, 2024
dc9b3af
other -> remaining
dpercy May 10, 2024
70fd686
however, however however; however.
dpercy May 10, 2024
9953a7b
equally bad
dpercy May 10, 2024
9948cf8
Merge remote-tracking branch 'origin/master' into PERF-5374-comments
dpercy Jun 17, 2024
d691dd8
fix bad merge
dpercy Jun 17, 2024
e12b6eb
remove "We expect ..." comment about SBE multiplanner
dpercy Jun 4, 2024
2b0b7bb
avoid "empty data" wording
dpercy Jun 4, 2024
c9d3933
typo
dpercy Jun 17, 2024
d0b801d
update docs
dpercy Jun 17, 2024
69cbdc6
rephrase SBE multiplanner as "historical"
dpercy Jun 17, 2024
8524dec
note about residual selectivity
dpercy Jun 17, 2024
d61a02b
update docs
dpercy Jun 17, 2024
e52494b
appease linter by adding keyword to unchanged file
dpercy Jun 17, 2024
d5c7d76
dont compare
dpercy Jun 18, 2024
1830416
the multiplanner handles group
dpercy Jun 18, 2024
42a536b
empty bounds
dpercy Jun 18, 2024
b5ba2ba
not large strings
dpercy Jun 18, 2024
539fad1
update docs
dpercy Jun 18, 2024
324a0c3
Merge branch 'master' into PERF-5374-comments
dpercy Jun 18, 2024
e9a2b5e
trailing spaces
dpercy Jun 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
138 changes: 62 additions & 76 deletions docs/generated/workloads.md
Original file line number Diff line number Diff line change
Expand Up @@ -4214,15 +4214,12 @@ https://docs.mongodb.com/manual/reference/operator/aggregation/setWindowFields/


### Description
The goal of this test is to exercise multiplanning. We create as many indexes as possible, and run
a query that makes all of them eligible, so we get as many competing plans as possible. We also
add a sort stage on an unindexed field, ensuring that every plan is a blocking plan. Because all
plans are blocking and return as many documents as possible, multiplanning will hit "max works"
instead of EOF of numToReturn. This maximizes the overhead of multiplanning on both classic and SBE.

We expect classic to have better latency and throughput than SBE on this workload,
and we expect the combination of classic planner + SBE execution (PM-3591) to perform about
as well as classic.
The goal of this test is to show how a blocking sort can increase the overhead of multiplanning.
We create as many indexes as possible, and run a query that makes all of them eligible, so we
get as many competing plans as possible. We also add a sort stage on an unindexed field,
ensuring that every plan is a blocking plan. Because all plans are blocking and return as many
documents as possible, multiplanning will hit "max works" instead of EOF or numToReturn.
This maximizes the overhead of multiplanning.



Expand All @@ -4233,13 +4230,14 @@ as well as classic.


### Description
The goal of this test is to exercise multiplanning. We create as many indexes as possible, and run a
query that makes all of them eligible, so we get as many competing plans as possible. Here, we do this on a
clustered collection that has very large strings as _id.
The goal of this test is to exercise multiplanning in the presence of clustered indexes. We
create as many indexes as possible, and run a query that makes all of them eligible, so we get
as many competing plans as possible. The collection is clustered and has very large strings as
_id.

We expect classic to have better latency and throughput than SBE on this workload,
and we expect the combination of classic planner + SBE execution (PM-3591) to perform about
as well as classic.
This workload is similar to 'Simple.yml' except that the collection is clustered. None of the
competing plans actually take advantage of the clustering (there is no bounded collection scan
plan). Maybe we expect the larger record IDs to make fetch take more wall clock time.



Expand Down Expand Up @@ -4278,10 +4276,6 @@ having predicates on all the fields, while only the predicate on field x1 has se
leads to many index seeks on the less effective indices (..., x1). Because every time we hit a non-
matching field we seek again, and the scan ends when we reach a non-matching x1.

We expect classic to have better latency and throughput than SBE on this workload,
and we expect the combination of classic planner + SBE execution (PM-3591) to perform about
as well as classic.



## [MultiPlanningReadsALotOfData](https://www.github.com/mongodb/genny/blob/master/src/workloads/query/multiplanner/MultiPlanningReadsALotOfData.yml)
Expand Down Expand Up @@ -4323,13 +4317,7 @@ indexes
### Description
The goal of this test is to exercise multiplanning with multikey indexes. We create many indexes and
run a query that makes all of them eligible, so we get as many competing plans as possible. Because
an IXSCAN of a multikey index has to deduplicate RIDs, a lot of space will be used. The classic
multi-planner will behave more optimally than the SBE multiplanner because it will cut off execution
when the one good plan reaches the end.

We expect classic to have better latency and throughput than SBE on this workload,
and we expect the combination of classic planner + SBE execution (PM-3591) to perform about
as well as classic.
an IXSCAN of a multikey index has to deduplicate RIDs, a lot of space will be used.



Expand All @@ -4340,15 +4328,11 @@ as well as classic.


### Description
The goal of this test is to exercise multiplanning. We create as many indexes as possible, and run a
query that makes all of them eligible, so we get as many competing plans as possible. We add a
group stage, which is blocking. The SBE multiplanner will multiplan group as it is a part of the
canonical query, but the classic multiplanner will not plan. This means the SBE multiplanner will
have the overhead of trial running blocking plans when compared to the classic multiplanner.

We expect classic to have better latency and throughput than SBE on this workload,
and we expect the combination of classic planner + SBE execution (PM-3591) to perform about
as well as classic.
This test was created to show how the multiplanner handles $group.
The query is essentially the one from 'Simple.yml': we have as many indexed predicates as
possible, to create as many indexed plans as possible, but only one of those predicates is
selective, which means only one of those plans is efficient. Where this test departs from
'Simple.yml' is by adding a $group stage after the access-path part of the query.



Expand All @@ -4360,13 +4344,9 @@ as well as classic.

### Description
The goal of this test is to exercise multiplanning. We create as many indexes as possible, and run a
query that makes all of them eligible, so we get as many competing plans as possible. All predicates
are very selective (match 0% of the documents). With zero results, we do no hit the EOF optimization
and all competing plans hit the works limit instead of document limit.

We expect classic to have better latency and throughput than SBE on this workload,
and we expect the combination of classic planner + SBE execution (PM-3591) to perform about
as well as classic.
query that makes all of them eligible, so we get as many competing plans as possible. However, all
the indexed predicates are very selective (match 0% of the documents). This should result in empty
index bounds, so multiplanning should finish immediately.



Expand All @@ -4391,6 +4371,10 @@ multi-planner for a few reasons:
2) When there are zero results, each plan has a productivity ratio of zero. This makes ties
likely during plan ranking, which can in turn lead to an incorrect plan choice.



### Keywords
multiplanner


## [NonBlockingVsBlocking](https://www.github.com/mongodb/genny/blob/master/src/workloads/query/multiplanner/NonBlockingVsBlocking.yml)
Expand All @@ -4400,16 +4384,19 @@ multi-planner for a few reasons:


### Description
The goal of this test is to exercise multiplanning. If the selectivity value is small enough (less
than 0.5), the optimal plan is to employ a blocking plan by scanning a segment of empty data and
conducting a blocking-sort operation, whereas the other plans' index provides the right sort
order, but requires a full scan, and every document is rejected after the FETCH stage. Because the
SBE multiplanner can't round-robin, it has a heuristic "try nonblocking plans first". This
scenario is a worst case for that heuristic, because we'll try the best plan last. Otherwise, an
IXSCAN and FETCH non-blocking plan will be used.
The goal of this test is to exercise multiplanning when both blocking and non-blocking plans are
available.

We expect classic to have better latency and throughput than SBE on this workload, and we expect
the combination of classic planner + SBE execution (PM-3591) to perform about as well as classic.
If the selectivity value is small enough (less than 0.5), the optimal plan is to scan a narrow
range of an index and then blocking sort. An alternative, suboptimal query plan does a full scan
of an index that provides the right sort order, and requires fetching each document before running
a very selective residual predicate: this means each getNext() has to scan many index entries
(1/selectivity on average).

This case shows that it's important for the multiplanner to round-robin the execution of the candidate
plans. Historically (in an alternative multiplanner based on SBE execution) we have tried a simpler
strategy that runs the candidates sequentially, starting with the nonblocking plans--this heuristic
does not work, because a nonblocking plan can still do an unbounded amount of work per getNext().



Expand All @@ -4423,15 +4410,11 @@ the combination of classic planner + SBE execution (PM-3591) to perform about as
The goal of this test is to exercise multiplanning. We create as many indexes as possible, and run a
query that makes all of them eligible, so we get as many competing plans as possible.

The original goal of this test was to demonstrate weaknesses of the SBE multiplanner when compared to
This test was originally created to demonstrate weaknesses of the SBE multiplanner when compared to
the classic multiplanner. Mainly, the SBE multiplanner can't round-robin between plans, which means it
has to run the list of plans sequentially, which means we can't short-circuit when the shortest-running
plan finishes.

We expect classic to have better latency and throughput than SBE on this workload,
and we expect the combination of classic planner + SBE execution (PM-3591) to perform about
as well as classic.



## [Subplanning](https://www.github.com/mongodb/genny/blob/master/src/workloads/query/multiplanner/Subplanning.yml)
Expand All @@ -4447,10 +4430,6 @@ query that makes all of them eligible, so we get as many competing plans as poss
The workload uses an $or query with 8 clauses each containing 8 predicates. Each branch have
only one selective predicate.

We expect classic to have better latency and throughput than SBE on this workload,
and we expect the combination of classic planner + SBE execution (PM-3591) to perform about
as well as classic.



## [UseClusteredIndex](https://www.github.com/mongodb/genny/blob/master/src/workloads/query/multiplanner/UseClusteredIndex.yml)
Expand All @@ -4460,13 +4439,13 @@ as well as classic.


### Description
The goal of this test is to exercise multiplanning. We create as many indexes as possible, and run a
query that makes all of them eligible, so we get as many competing plans as possible. Here, we do this on a
clustered collection and add a selective predicate on _id, so that the clustered index is a viable candidate plan.
The goal of this test is to exercise multiplanning in the presence of clustered indexes. We
create as many indexes as possible, and run a query that makes all of them eligible, so we get
as many competing plans as possible. The collection is clustered and one of the predicates is
on _id, which means a clustered collection scan is included in the competing plans.

We expect classic to have better latency and throughput than SBE on this workload,
and we expect the combination of classic planner + SBE execution (PM-3591) to perform about
as well as classic.
This workload is similar to 'Simple.yml' except for the collection being clustered, and the
extra predicate.



Expand All @@ -4477,17 +4456,24 @@ The goal of this test is to exercise multiplanning. We create as many indexes as


### Description
The goal of this test is to exercise multiplanning. We run the same query 7 times, each one with a
different selectivity value that we are comparing against x1, calcuated based on the number of
documents we want the query to match. This will help us measure the overhead of throwing out the
result set gathered during multi-planning when the result set exceeds 101 documents. Unlike many
of the other multiplanner/ workloads, we only test with 2 indexes here, because 2 indexes is a
worst case for throwing away results. Having more indexes increases planning time, but not query
execution time, so having more indexes makes the *relative* cost of throwing away results smaller.
The goal of this test is to measure the overhead of "throwing out" the initial results returned by
multiplanning.

When a query runs with Classic multiplanner + Classic execution, then when multiplanning finishes
the query can resume running and reuse the partial results it gathered during multiplanning. By
contrast when running with SBE execution, the query has
to start over--unless it already finished during multiplanning. This means SBE has a
discontinuity in performance as the size of the result set grows: when it crosses from 100 to
102 documents, it has to recompute those first ~100 documents.

To measure this, we run the same query 7 times, each one with a different selectivity value.
For example, in phase 'MultiplannerWith50ExpectedResults' we choose a selectivity of
'50 / collectionSize' to make the query return (approximately) 50 documents.

We expect classic to have better latency and throughput than SBE on this workload,
and we expect the combination of classic planner + SBE execution (PM-3591) to perform about
as well as classic.
Unlike many of the other multiplanner/ workloads, we only test with 2 indexes here, because
2 indexes is a worst case for throwing away results. Having more indexes increases planning
time, but not query execution time, so having more indexes makes the *relative* cost of
throwing away results smaller.



Expand Down
15 changes: 6 additions & 9 deletions src/workloads/query/multiplanner/BlockingSort.yml
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
SchemaVersion: 2018-07-01
Owner: "@mongodb/query"
Description: |
The goal of this test is to exercise multiplanning. We create as many indexes as possible, and run
a query that makes all of them eligible, so we get as many competing plans as possible. We also
add a sort stage on an unindexed field, ensuring that every plan is a blocking plan. Because all
plans are blocking and return as many documents as possible, multiplanning will hit "max works"
instead of EOF of numToReturn. This maximizes the overhead of multiplanning on both classic and SBE.

We expect classic to have better latency and throughput than SBE on this workload,
and we expect the combination of classic planner + SBE execution (PM-3591) to perform about
as well as classic.
The goal of this test is to show how a blocking sort can increase the overhead of multiplanning.
We create as many indexes as possible, and run a query that makes all of them eligible, so we
get as many competing plans as possible. We also add a sort stage on an unindexed field,
ensuring that every plan is a blocking plan. Because all plans are blocking and return as many
documents as possible, multiplanning will hit "max works" instead of EOF or numToReturn.
This maximizes the overhead of multiplanning.

GlobalDefaults:
dbname: &db test
Expand Down
13 changes: 7 additions & 6 deletions src/workloads/query/multiplanner/ClusteredCollection.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
SchemaVersion: 2018-07-01
Owner: "@mongodb/query"
Description: |
The goal of this test is to exercise multiplanning. We create as many indexes as possible, and run a
query that makes all of them eligible, so we get as many competing plans as possible. Here, we do this on a
clustered collection that has very large strings as _id.
The goal of this test is to exercise multiplanning in the presence of clustered indexes. We
create as many indexes as possible, and run a query that makes all of them eligible, so we get
as many competing plans as possible. The collection is clustered and has very large strings as
_id.
We expect classic to have better latency and throughput than SBE on this workload,
and we expect the combination of classic planner + SBE execution (PM-3591) to perform about
as well as classic.
This workload is similar to 'Simple.yml' except that the collection is clustered. None of the
competing plans actually take advantage of the clustering (there is no bounded collection scan
plan). Maybe we expect the larger record IDs to make fetch take more wall clock time.
GlobalDefaults:
dbname: &db test
Expand Down
4 changes: 0 additions & 4 deletions src/workloads/query/multiplanner/ManyIndexSeeks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@ Description: |
leads to many index seeks on the less effective indices (..., x1). Because every time we hit a non-
matching field we seek again, and the scan ends when we reach a non-matching x1.

We expect classic to have better latency and throughput than SBE on this workload,
and we expect the combination of classic planner + SBE execution (PM-3591) to perform about
as well as classic.

GlobalDefaults:
dbname: &db test
# Collection name used for queries.
Expand Down
8 changes: 1 addition & 7 deletions src/workloads/query/multiplanner/MultikeyIndexes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,7 @@ Owner: "@mongodb/query"
Description: |
The goal of this test is to exercise multiplanning with multikey indexes. We create many indexes and
run a query that makes all of them eligible, so we get as many competing plans as possible. Because
an IXSCAN of a multikey index has to deduplicate RIDs, a lot of space will be used. The classic
multi-planner will behave more optimally than the SBE multiplanner because it will cut off execution
when the one good plan reaches the end.
We expect classic to have better latency and throughput than SBE on this workload,
and we expect the combination of classic planner + SBE execution (PM-3591) to perform about
as well as classic.
an IXSCAN of a multikey index has to deduplicate RIDs, a lot of space will be used.
GlobalDefaults:
dbname: &db test
Expand Down
14 changes: 5 additions & 9 deletions src/workloads/query/multiplanner/MultiplannerWithGroup.yml
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
SchemaVersion: 2018-07-01
Owner: "@mongodb/query"
Description: |
The goal of this test is to exercise multiplanning. We create as many indexes as possible, and run a
query that makes all of them eligible, so we get as many competing plans as possible. We add a
group stage, which is blocking. The SBE multiplanner will multiplan group as it is a part of the
canonical query, but the classic multiplanner will not plan. This means the SBE multiplanner will
have the overhead of trial running blocking plans when compared to the classic multiplanner.

We expect classic to have better latency and throughput than SBE on this workload,
and we expect the combination of classic planner + SBE execution (PM-3591) to perform about
as well as classic.
This test was created to show how the multiplanner handles $group.
The query is essentially the one from 'Simple.yml': we have as many indexed predicates as
possible, to create as many indexed plans as possible, but only one of those predicates is
selective, which means only one of those plans is efficient. Where this test departs from
dstorch marked this conversation as resolved.
Show resolved Hide resolved
'Simple.yml' is by adding a $group stage after the access-path part of the query.

GlobalDefaults:
dbname: &db test
Expand Down
10 changes: 3 additions & 7 deletions src/workloads/query/multiplanner/NoResults.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,9 @@ SchemaVersion: 2018-07-01
Owner: "@mongodb/query"
Description: |
The goal of this test is to exercise multiplanning. We create as many indexes as possible, and run a
query that makes all of them eligible, so we get as many competing plans as possible. All predicates
are very selective (match 0% of the documents). With zero results, we do no hit the EOF optimization
and all competing plans hit the works limit instead of document limit.

We expect classic to have better latency and throughput than SBE on this workload,
and we expect the combination of classic planner + SBE execution (PM-3591) to perform about
as well as classic.
query that makes all of them eligible, so we get as many competing plans as possible. However, all
the indexed predicates are very selective (match 0% of the documents). This should result in empty
index bounds, so multiplanning should finish immediately.

GlobalDefaults:
dbname: &db test
Expand Down
2 changes: 2 additions & 0 deletions src/workloads/query/multiplanner/NoSuchField.yml
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've fixed this description as part of #1224 which I merged this morning. So when you merge with the latest from master, I think this PR should end up in a state where it does not make any changes to this file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, after updating it looks like NoSuchField.yml is unchanged in this PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Except the linter complained so I had to add a "Keywords" section.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, why did the linter complain for this workload but not the others? In your branch, only two of the multiplanner workloads have the keyword specified. I guess you should either add Keywords to all the multi-planner workloads in this patch or file a ticket about doing so later. (If we file a ticket, it's probably something we would stick into the neweng bucket?)

Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ Description: |
candidate plans and none of them produce any results.
2) When there are zero results, each plan has a productivity ratio of zero. This makes ties
likely during plan ranking, which can in turn lead to an incorrect plan choice.
Keywords:
- multiplanner

GlobalDefaults:
dbname: &db test
Expand Down