question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

ParameterReplacer performance

See original GitHub issue

So doing some performance profiling recently we’ve noticed that our issues weren’t SQL times but related to the ParameterReplacer class.

Now I’m not saying this class is overly slow - we’re passing in a reasonably big query, but we have noticed that each .When or .WhenWhere appened to the query makes a larger and larger impact than the last one. To the point where one call to ParameterReplacer.Replace is taking over 900ms.

Call to Replace 897.8ms
Expression = ctx.Set().AsSplitQuery().IncludeDeletedWhen(ctx, (Convert(arg_Dynamic_mergedArgs_96aba847-67ac-4181-892e-99d616252ae3.filterType, Nullable`1) == Convert(Lost, Nullable`1))).WhereWhen(i => arg_Dynamic_mergedArgs_96aba847-67ac-4181-892e-99d616252ae3.jobTypes.Contains(i.TypeId), (arg_Dynamic_mergedArgs_96aba847-67ac-4181-892e-99d616252ae3.jobTypes != null)).WhereWhen(i => arg_Dynamic_mergedArgs_96aba847-67ac-4181-892e-99d616252ae3.stages.Contains(i.StageId), (arg_Dynamic_mergedArgs_96aba847-67ac-4181-892e-99d616252ae3.stages != null)).WhereWhen(i => (Convert(i.FactoryId, Nullable`1) == arg_Dynamic_mergedArgs_96aba847-67ac-4181-892e-99d616252ae3.factoryId), arg_Dynamic_mergedArgs_96aba847-67ac-4181-892e-99d616252ae3.factoryId.HasValue).Where(i => True).Where(i => True).Where(i => True).Where(i => True).Where(i => True).Where(i => True).Where(i => True).Where(i => True).Where(i => True).Where(i => True).OrderBy(Param_0 => Param_0.ProdOrder) 

(yes there’s a lotof .Where(i => True) in there, i had actual where whens in there before but noticed it didn’t seem to matter in terms of performance, each .Where(i => True) added a significant impact.)

No specific method seems to take a lot of time it’s just visiting a lot of things.

Thoughts

  • Even a tiny fix to the methods on this class would have a large benefit since it seems to go quite deep
  • Expressions themselves don’t seem to be cached at all (just the GraphQL doc) maybe there’s something we could do there

Gonna dig in to this deeper.

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:19 (11 by maintainers)

github_iconTop GitHub Comments

1reaction
lukemurraycommented, Mar 26, 2023

Closing as there were have been improvements. And future changes we’ll check against the benchmarks to make sure things do not regress and hopefully get better.

1reaction
bzbettycommented, Oct 22, 2022

increased the last test to have 20 WhereWhens and it finally seems to be quite slow (~15-20s per run - i’ll post stats once it finishes running).

The query doesn’t seem unreasonable, i did cheap out a bit and just duplicated the queries but I don’t think that many filters is unreasonable in a large project.

(ctx, args) => ctx.Set<Movie>()
                    .AsSplitQuery()
                    .AsNoTracking()
                    .IgnoreQueryFilters()
                    .WhereWhen(i => i.Name == args.Name, !string.IsNullOrWhiteSpace(args.Name))
                    .WhereWhen(i => i.Director.FirstName == args.DirectorName, !string.IsNullOrWhiteSpace(args.DirectorName))
                    .WhereWhen(i => i.Director.Id == args.DirectorId, args.DirectorId.HasValue)
                    .WhereWhen(i => i.Actors.Any(x => x.Id == args.ActorId), !string.IsNullOrWhiteSpace(args.ActorName))
                    .WhereWhen(i => i.Actors.Any(x => x.FirstName == args.ActorName), args.ActorId.HasValue)
                    .WhereWhen(i => i.Rating > args.RatingMin, args.RatingMin.HasValue)
                    .WhereWhen(i => i.Rating < args.RatingMax, args.RatingMax.HasValue)
                    .WhereWhen(i => i.Released > args.ReleasedAfter, args.ReleasedAfter.HasValue)
                    .WhereWhen(i => i.Released < args.ReleasedBefore, args.ReleasedBefore.HasValue)
                    .WhereWhen(i => args.Genres.Contains(i.Genre.Name), args.Genres.Length > 0)
                    .WhereWhen(i => i.Name == args.Name, !string.IsNullOrWhiteSpace(args.Name))
                    .WhereWhen(i => i.Director.FirstName == args.DirectorName, !string.IsNullOrWhiteSpace(args.DirectorName))
                    .WhereWhen(i => i.Director.Id == args.DirectorId, args.DirectorId.HasValue)
                    .WhereWhen(i => i.Actors.Any(x => x.Id == args.ActorId), !string.IsNullOrWhiteSpace(args.ActorName))
                    .WhereWhen(i => i.Actors.Any(x => x.FirstName == args.ActorName), args.ActorId.HasValue)
                    .WhereWhen(i => i.Rating > args.RatingMin, args.RatingMin.HasValue)
                    .WhereWhen(i => i.Rating < args.RatingMax, args.RatingMax.HasValue)
                    .WhereWhen(i => i.Released > args.ReleasedAfter, args.ReleasedAfter.HasValue)
                    .WhereWhen(i => i.Released < args.ReleasedBefore, args.ReleasedBefore.HasValue)
                    .WhereWhen(i => args.Genres.Contains(i.Genre.Name), args.Genres.Length > 0)
Read more comments on GitHub >

github_iconTop Results From Across the Web

Performance of compiling a expression
I have the following method and curious about performance impact of compiling Expression. public async Task<Response<TResult>> Execute<TApi, ...
Read more >
Specification pattern: C# implementation
Specification pattern is a pattern that allows us to encapsulate some piece of domain knowledge into a single unit - specification - and...
Read more >
DAX Articles & Performance Tuning Stuff
DAX with Tabular Model Articles & Performance Tuning Stuff DAX is a wonderful & very fast language. ... 1, Free Tool – DAX...
Read more >
Add the XPQuery<T>.TransformExpression<TResult> ...
I like the idea to write TransformExpression function to create and validate expressions for my calculated fields, but currently i can only ...
Read more >
Combine BinaryExpression and Expression<Func<dynamic ...
This is a non generic method which combines the exiting filter with passed filter using AndAlso (C# && ) operator and shows the...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found