简体   繁体   English

Linq To Sql令人惊讶的快速撤退数据。 它是否比ADO快10倍是正常的吗?

[英]Linq To Sql surprisingly fast retreving data. Is it normal that it is 10x faster than ADO?

I'm currently learning Linq to Sql and Im very surprised by the performance of selecting data. 我正在学习Linq to Sql,我对选择数据的性能非常惊讶。 I'm retreving joined data from few tables. 我正在从几张桌子上撤回加入的数据。 I select about 40k of rows. 我选择了大约40k的行。 Mapping this data to objects using ADO times about 35s, using NHbiernate times about 130s and what is suspicious using Linq To Sql only 3,5s. 使用大约35秒的ADO时间将此数据映射到对象,使用大约130秒的NHbiernate时间以及使用Linq To Sql只有3,5s的可疑内容。 Additionally I would like to write that I'm using immediately loading which looks like: 此外,我想写我正在使用立即加载看起来像:

THESIS th = new THESIS(connectionString);
DataLoadOptions dlo = new DataLoadOptions();
dlo.LoadWith<NumericFormula>(x => x.RPN);
dlo.LoadWith<RPN>(x => x.RPNDetails);
dlo.LoadWith<RPNDetail>(x => x.Parameter);
th.LoadOptions = dlo;
th.Log = Console.Out;

Looking to the logs when I'm iterating I can't see that Linq To Sql generate some additional queries to database. 在我迭代时查看日志我看不到Linq To Sql对数据库生成一些额外的查询。

I'm very surprised by huge differences in performance and I wonder that maybe I don't understand something. 我对性能的巨大差异感到非常惊讶,我想也许我不明白。

Could someone explain me why it works so fast? 有人可以解释一下为什么它的工作如此之快? To measure time I'm using Stopwatch class. 测量时间我正在使用秒表课程。

ADO.NET Code: ADO.NET代码:

public static List<NumericFormulaDO> SelectAllNumericFormulas()
{
    var nFormulas = new List<NumericFormulaDO>();

    string queryString = @"
        SELECT *
        FROM    NumericFormula nf 
                Left Join Unit u on u.Unit_Id = nf.Unit_Id 
                Left Join UnitType ut on ut.UnitType_Id = u.UnitType_Id 
                Join RPN r on r.RPN_Id = nf.RPN_Id 
                Join RPNDetails rd on rd.RPN_Id = r.RPN_Id 
                Join Parameter par on par.Parameter_Id = rd.Parameter_Id where nf.NumericFormula_Id<=10000";

    using (var connection = new SqlConnection(connectionString))
    {
        var command = new SqlCommand(queryString, connection);
        connection.Open();
        using (var reader = command.ExecuteReader())
        {
            while (reader.Read())
            {
                var det = new RPNDetailsDO();
                det.RPNDetails_Id = Int32.Parse(reader["RPNDetails_Id"].ToString());
                det.RPN_Id = Int32.Parse(reader["RPN_Id"].ToString());
                det.Identifier = reader["Identifier"].ToString();
                det.Parameter.Architecture = reader["Architecture"].ToString();
                det.Parameter.Code = reader["Code"].ToString();
                det.Parameter.Description = reader["Description"].ToString();
                det.Parameter.Parameter_Id = Int32.Parse(reader["Parameter_Id"].ToString());
                det.Parameter.ParameterType = reader["ParameterType"].ToString();
                det.Parameter.QualityDeviationLevel = reader["QualityDeviationLevel"].ToString();

                if (nFormulas.Count > 0)
                {
                     if (nFormulas.Any(x => x.RPN.RPN_Id == Int32.Parse(reader["RPN_Id"].ToString())))
                     {
                         nFormulas.First(x=>x.RPN.RPN_Id == Int32.Parse(reader["RPN_Id"].ToString())).RPN.RPNDetails.Add(det);
                     }
                     else
                     {
                         NumericFormulaDO nFormula = CreatingNumericFormulaDO(reader, det);
                         nFormulas.Add(nFormula);
                         //System.Diagnostics.Trace.WriteLine(nFormulas.Count.ToString());
                     }
                }
                else
                {
                     NumericFormulaDO nFormula = CreatingNumericFormulaDO(reader, det);
                     nFormulas.Add(nFormula);
                     //System.Diagnostics.Trace.WriteLine(nFormulas.Count.ToString());
                }
            }
        }
    }

    return nFormulas;
}

private static NumericFormulaDO CreatingNumericFormulaDO(SqlDataReader reader, RPNDetailsDO det)
{
    var nFormula = new NumericFormulaDO();
    nFormula.CalculateDuringLoad = Boolean.Parse(reader["CalculateDuringLoad"].ToString());
    nFormula.NumericFormula_Id = Int32.Parse(reader["NumericFormula_Id"].ToString());
    nFormula.RPN.RPN_Id = Int32.Parse(reader["RPN_Id"].ToString());
    nFormula.RPN.Formula = reader["Formula"].ToString();
    nFormula.Unit.Name = reader["Name"].ToString();

    if (reader["Unit_Id"] != DBNull.Value)
    {
        nFormula.Unit.Unit_Id = Int32.Parse(reader["Unit_Id"].ToString());
        nFormula.Unit.UnitType.Type = reader["Type"].ToString();
        nFormula.Unit.UnitType.UnitType_Id = Int32.Parse(reader["UnitType_Id"].ToString());
    }
    nFormula.RPN.RPNDetails.Add(det);
    return nFormula;
}

LINQ to SQL Code: LINQ to SQL代码:

THESIS th = new THESIS(connectionString);
DataLoadOptions dlo = new DataLoadOptions();
dlo.LoadWith<NumericFormula>(x => x.RPN);
dlo.LoadWith<RPN>(x => x.RPNDetails);
dlo.LoadWith<RPNDetail>(x => x.Parameter);
th.LoadOptions = dlo;
th.Log = Console.Out;
var nFormulas = 
    th.NumericFormulas.ToList<NumericFormula>();

NHibernate Code: NHibernate代码:

IQueryable<NumericFormulaDO> nFormulas =
    session.Query<NumericFormulaDO>()
        .Where(x=>x.NumericFormula_Id <=10000);

List<NumericFormulaDO> nForList =
    new List<NumericFormulaDO>();

nForList = nFormulas.ToList<NumericFormulaDO>();

Related to your comments you can see that in ADO I'm using SqlReader and in LINQ I try to use immediate execution. 与您的注释相关,您可以看到在ADO中我使用的是SqlReader ,在LINQ中我尝试使用立即执行。

Of course it is possible that my mapping "algorithm" in ADO part it's not very good but NHibernate is much more slow than ADO (4x slower) so I wonder if for sure is everything alright in LINQ to SQL part because I think in NHibernate is everything good and after all is much more slow than little confusing ADO part. 当然,我在ADO中的映射“算法”可能不是很好但是NHibernate比ADO慢得多(慢4倍),所以我想知道在LINQ to SQL部分是否一切都好,因为我认为在NHibernate中是一切都很好,毕竟比ADO部分的混乱要慢得多。

Thank you guys for responses. 谢谢大家的回复。

LINQ-to-SQL consumes ADO.NET and has additional overheads, so no: it shouldn't be faster unless it isn't doing the same work. LINQ-to-SQL消耗ADO.NET并且有额外的开销,所以没有:它不应该更快,除非它没有做同样的工作。 There was mention of access via ordinals vs names, but frankly that affects micro-seconds, not seconds. 通过序数和名称提到了访问权限,但坦率地说这会影响微秒,而不是秒。 It won't explain an order of magnitude change. 它不会解释一个数量级的变化。

The only way to answer this is to trace what LINQ-to-SQL is doing. 回答这个问题的唯一方法是跟踪LINQ-to-SQL正在做什么。 Fortunately this is simple - you can just do: 幸运的是,这很简单 - 您可以这样做:

dbContext.Log = Console.Out;

which will write the TSQL is executes to the console. 将编写TSQL执行到控制台。 There are two options then: 那么有两种选择:

  1. you discover the TSQL isn't doing the same thing (maybe it isn't eager-loading) 你发现TSQL没有做同样的事情(也许它不是急于加载)
  2. you discover the TSQL is valid (=doing the same), but has a better plan - in which case... "borrow" it :p 你发现TSQL是有效的(=做同样的事情),但有一个更好的计划 - 在这种情况下......“借”它:p

Once you have the TSQL to compare, test that side-by-side, so you are testing the same work. 一旦你的TSQL比较, 测试并排侧,所以要测试同样的工作。 If you want the convenience without the overheads, I'd look at "dapper" - takes away the boring grunt-work of mapping readers to objects, but very optimised. 如果你想要没有开销的便利,我会看看“小巧玲珑” - 带走将阅读器映射到对象的枯燥乏味的工作,但是非常优化。

Rewritten ADO.NET code based on above remarks, this should be a lot faster. 基于上述评论重写ADO.NET代码,这应该快得多。 You could still improve by using the ordinal value instead of the column names and by reading the fields in exactly the same order as in the query, but those are micro optimizations. 您仍然可以通过使用序数值而不是列名来改进,并以与查询中完全相同的顺序读取字段,但这些是微优化。

I've also removed a couple of duplications. 我也删除了几个重复。 Y ou might also want to check how to improve the performance of typecasting and conversions , as the Parse(ToString) route is very inefficient and can cause very strange issues when running with systems running in different languages. 您可能还想检查如何提高类型转换和转换的性能 ,因为Parse(ToString)路由效率非常低,并且在运行不同语言的系统运行时会导致非常奇怪的问题。 There's also a chance of dataloss when doing these conversions when decimal, float or doubles are involved, as not all of their values can be translated to strings correctly (or can't roundtrip back). 当涉及十进制,浮点或双精度时,进行这些转换时也有可能存在数据转换,因为并非它们的所有值都可以正确地转换为字符串(或者不能往返)。

public static List<NumericFormulaDO> SelectAllNumericFormulas()
{
    var nFormulas = new Dictionary<int, NumericFormulaDO>();

    string queryString = @"
    SELECT *
    FROM    NumericFormula nf 
            Left Join Unit u on u.Unit_Id = nf.Unit_Id 
            Left Join UnitType ut on ut.UnitType_Id = u.UnitType_Id 
            Join RPN r on r.RPN_Id = nf.RPN_Id 
            Join RPNDetails rd on rd.RPN_Id = r.RPN_Id 
            Join Parameter par on par.Parameter_Id = rd.Parameter_Id where nf.NumericFormula_Id<=10000";

    using (var connection = new SqlConnection(connectionString))
    {  
        connection.Open();
        using (var command = new SqlCommand(queryString, connection));
        using (var reader = command.ExecuteReader())
        {
            while (reader.Read())
            {
                var det = new RPNDetailsDO();
                det.RPNDetails_Id = (int) reader.GetValue("RPNDetails_Id");
                det.RPN_Id = (int) reader.GetValue("RPN_Id");
                det.Identifier = (string) reader.GetValue("Identifier");
                det.Parameter.Architecture = (string)reader.GetValue("Architecture");
                det.Parameter.Code = (string)reader.GetValue("Code");
                det.Parameter.Description = (string)reader.GetValue("Description");
                det.Parameter.Parameter_Id = (int) reader.GetValue("Parameter_Id");
                det.Parameter.ParameterType = (string)reader.GetValue("ParameterType");
                det.Parameter.QualityDeviationLevel = (string)reader.GetValue("QualityDeviationLevel");

                NumericFormulaDO parent = null;
                if (!nFormulas.TryGetValue((int)reader.GetValue("RPN_Id"), out parent)
                {
                    parent = CreatingNumericFormulaDO(reader, det);
                    nFormulas.Add(parent.RPN.RPNID, parent);
                }
                else
                {
                    parent.RPN.RPNDetails.Add(det);
                }
            }
        }
    }

    return nFormulas.Values.ToList();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM