As a general rule the async methods will have *slightly* more overhead than the sync methods. So an *individual* async method call will be slightly slower than the sync equivalent. But in a heavily loaded system it is likely that an async implementation will handle higher aggregate throughput since it will require fewer threads.
One combination that is not recommended is calling an async method and then calling Wait on the task. If you're going to block on the result you're better of calling the sync method in the first place.
Using Parallel.ForEach for benchmarks is non-deterministic because you don't know what degree of parallelism Parallel.ForEach will use. In fact, Parallel.ForEach will tune the degree of parallelism while the loop is executing, so it can easily be using different degrees of parallelism during the same loop.
Your TestSync and TestAsyncAwait methods are calling different overloads of Parallel.ForEach and we don't know if those two overloads use different heuristics for tuning the degree of parallelism. Most likely they do since you are seeing a larger performance difference than expected between the sync and async implementations.
The default connection pool size is 100 connections. So once 100 Threads/Tasks are using a connection, subsequent Threads/Tasks have to wait for a connection to become available. The default size of the connection pool wait queue is 500. So if you have a degree of parallelism that is over 600 you are subject to MongoWaitQueueFullExceptions. Also, if 500 Threads/Tasks are waiting for a connection it is likely or possible that some of them will get a TimeoutException if they have to wait too long.
It is important to keep the degree of parallelism and the size of the connection pool matched.
As to whether you should use sync or async, you should be able to achieve your goals with either approach. Just choose the one you prefer or are more comfortable with.