zzzprojects / System.Linq.Dynamic.Core

The .NET Standard / .NET Core version from the System Linq Dynamic functionality.
https://dynamic-linq.net/
Apache License 2.0
1.55k stars 228 forks source link

Basic performance consideration question #781

Closed kgreen24 closed 6 months ago

kgreen24 commented 6 months ago

Hello all,

I'm just trying this package out for the first time. It definitely works but one thing I noticed is that there's about a 1-2 second time to execute the rule the first time, and then every other time it takes like 0 - 1 millisecond. Here's some example code from a unit test I wrote:


            var rules = new List<TestRule>();
            for (var i = 0; i < 1000; i++)
            {
                rules.Add(GetFakeRule());
            }

            rules.Add(new TestRule
            {
                PassCondition = RulePassCondition.All,
                Conditions = new List<TestRuleCondition>
                {
                    new TestRuleCondition
                    {
                        FieldName = "Memo",
                        Predicate = TestRulePredicate.Equals,
                        FieldValue = "There",
                        Numeric = false
                    },
                    new TestRuleCondition
                    {
                        FieldName = "Amount",
                        Predicate = TestRulePredicate.GreaterThan,
                        FieldValue = "90",
                        Numeric = true
                    }
                }
            });

            var transactions = new[]
            {
                new TestTransactionData
                {
                    Memo = "There",
                    Amount = 92.35m
                },
                new TestTransactionData
                {
                    Memo = "Hello",
                    Amount = 45m
                },
                new TestTransactionData
                {
                    Memo = "There",
                    Amount = 99m
                }
            };

            var queryable = transactions.AsQueryable();

            var sw = new Stopwatch();
            foreach (var rule in rules)
            {
                sw.Start();
                var dynamicRule = rule.ToDynamicLinqRule();

                var result = queryable
                    .Where(dynamicRule.Expression, dynamicRule.Arguments)
                    .ToList();
                sw.Stop();
                Console.WriteLine($"{result.Count} {sw.ElapsedMilliseconds}");
                sw.Reset();
            }

I came up with a test rule class and an extension method "ToDynamicLinqRule" which returned the string of the expression with @0, @1, etc...and an Arguments array of type object[].

I noticed every time the first rule that ran took 1000-2000 ms to run, then every other one took about 0ms or 1ms. Is this expected? Are there any best practices to keep in mind about how to use this package to maximize performance?

StefH commented 6 months ago

The (dynamic) types used in the query need to loaded from the assembly-domain. That's the reason it's slow the first time. But the next calls are quick because these types are cached.