即使在处理了Context之后,Entity Framework Core是否也会缓存结果

时间:2016-12-16 12:13:55

标签: c# entity-framework-core

我正在比较不同ORM库和ADO.NET的对象实现速度。测试包括查询1次,10次,100次和1000次结果11次(我将调用1次)并再次重复整次测试10次,因此每次查询测试有10次。

1000查询没有跟踪实体的结果很有意思,因为期望第一次执行查询非常慢,以下(2-11)更快但下面的设置(2-10)比ADO快.NET!

EF Core测试代码。 Keys是11维和1000列的2维数组。

    public override async Task TestFindByPK(int[,] keys)
    {
        // force load all assemblies before real executing
        using (var forceLoad = new AdventureWorks2012Context())
        {
            var ignore = await forceLoad.ErrorLog.ToListAsync();
        }

        for (var t = 0; t < 10; t++)
        {
            using (var context = new AdventureWorks2012Context())
            {
                context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
                var stopWatch = new Stopwatch();

                for (var r = 0; r < keys.GetLength(0); r++)
                {
                    List<int> rows = GetRow(ref keys, r);
                    stopWatch.Restart();
                    var result = await context.SalesOrderHeader.Where(so => rows.Contains(so.SalesOrderId)).ToListAsync();
                    stopWatch.Stop();
                    await PrintTestFindByPKReport(stopWatch.ElapsedMilliseconds);
                }
            }

            Log.WriteLine($"Finish {t + 1} run{Environment.NewLine}");
            Thread.Sleep(TimeSpan.FromSeconds(2));
        }

        await Log.WriteLineAsync($"Complete on {DateTime.Now.ToShortTimeString()}{Environment.NewLine}");
    }

我猜测必须缓存查询结果,以便使用相同键的以下测试集可以从缓存中检索结果,否则EF Core必须比ADO.NET慢。

所以,问题1,EF Core是否在指定没有跟踪结果时缓存查询结果?

如果ADO.NET测试代码效率不高,这是ADO.NET测试的代码。

    public override async Task TestFindByPK(int[,] keys)
    {
        await PreloadAssemblies();
        var sql = "SELECT * FROM Sales.SalesOrderHeader WHERE SalesOrderID IN " + CreateInSQLCommand(keys.GetLength(1));
        SqlConnection conn = null;
        var stopWatch = new Stopwatch();

        for (var t = 0; t < 10; t++)
        {
            try
            {
                conn = new SqlConnection(ConnectionString);
                conn.Open();
                var sqlCmd = new SqlCommand(sql, conn);

                for (var r = 0; r < keys.GetLength(0); r++)
                {
                    var rows = GetRow(ref keys, r);
                    stopWatch.Restart();
                    sqlCmd.Parameters.Clear();
                    sqlCmd.Parameters.AddRange(CreateParamForInClause(rows));
                    var reader = await sqlCmd.ExecuteReaderAsync();
                    SalesOrderHeaderSQLserver salesOrderHeader = null;

                    while (await reader.ReadAsync())
                    {
                        salesOrderHeader = new SalesOrderHeaderSQLserver();
                        salesOrderHeader.SalesOrderId = reader.GetInt32(0);
                        salesOrderHeader.RevisionNumber = reader.GetByte(1);
                        salesOrderHeader.OrderDate = reader.GetDateTime(2);
                        salesOrderHeader.DueDate = reader.GetDateTime(3);
                        salesOrderHeader.ShipDate = await ConvertTo<DateTime?>(reader, 4);
                        salesOrderHeader.Status = reader.GetByte(5);
                        salesOrderHeader.OnlineOrderFlag = reader.GetBoolean(6);
                        salesOrderHeader.SalesOrderNumber = reader.GetString(7);
                        salesOrderHeader.PurchaseOrderNumber = await ConvertTo<string>(reader, 8);
                        salesOrderHeader.AccountNumber = await ConvertTo<string>(reader, 9);
                        salesOrderHeader.CustomerID = reader.GetInt32(10);
                        salesOrderHeader.SalesPersonID = await ConvertTo<int?>(reader, 11);
                        salesOrderHeader.TerritoryID = await ConvertTo<int?>(reader, 12);
                        salesOrderHeader.BillToAddressID = reader.GetInt32(13);
                        salesOrderHeader.ShipToAddressID = reader.GetInt32(14);
                        salesOrderHeader.ShipMethodID = reader.GetInt32(15);
                        salesOrderHeader.CreditCardID = await ConvertTo<int?>(reader, 16);
                        salesOrderHeader.CreditCardApprovalCode = await ConvertTo<string>(reader, 17);
                        salesOrderHeader.CurrencyRateID = await ConvertTo<int?>(reader, 18);
                        salesOrderHeader.SubTotal = reader.GetDecimal(19);
                        salesOrderHeader.TaxAmt = reader.GetDecimal(20);
                        salesOrderHeader.Freight = reader.GetDecimal(21);
                        salesOrderHeader.TotalDue = reader.GetDecimal(22);
                        salesOrderHeader.Comment = await ConvertTo<string>(reader, 23);
                        salesOrderHeader.Rowguid = reader.GetGuid(24);
                        salesOrderHeader.ModifiedDate = reader.GetDateTime(25);
                    }

                    stopWatch.Stop();
                    reader.Close();
                    await PrintTestFindByPKReport(stopWatch.ElapsedMilliseconds);
                }

            }
            catch (SqlException ex)
            {
                Console.WriteLine($"Exception message : {ex.Message}");
            }
            finally
            {
                conn.Dispose();
            }

            Log.WriteLine($"Finish {t + 1} run{Environment.NewLine}");
            Thread.Sleep(TimeSpan.FromSeconds(2));
        }

        await Log.WriteLineAsync($"Complete on {DateTime.Now.ToShortTimeString()}" + Environment.NewLine);
    }

其他奇怪的是第一个集总是慢于下面的集,我知道查询执行的时候它必须被处理并转换为相应的SQL命令,但它是缓存,但为什么2-11慢于以下测试集(它比第一次快得多)。

是否因为如果一组值不同,带有一组值的IN子句被视为不同?

0 个答案:

没有答案