Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/86.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么人们说SqlDataReader.GetXXX(i)比SqlDataReader[i]快?_C#_Sql_Performance_Ado.net - Fatal编程技术网

C# 为什么人们说SqlDataReader.GetXXX(i)比SqlDataReader[i]快?

C# 为什么人们说SqlDataReader.GetXXX(i)比SqlDataReader[i]快?,c#,sql,performance,ado.net,C#,Sql,Performance,Ado.net,更新:事实证明反射也不一定要慢。使用Fasterflect(http://www.codeproject.com/Articles/38840/Fasterflect-a-fast-and-simple-API-for-Reflection-i). 它使反射速度提高100倍(我指的是最字面的“字面”一词,而不是经常被误用的比喻) 我的代码现在可以加载数据并将数据放入我的业务对象,就像SQLServerManagementStudio在表上执行select*一样快 我刚刚运行了这段代码,检查表

更新:事实证明反射也不一定要慢。使用Fasterflect(http://www.codeproject.com/Articles/38840/Fasterflect-a-fast-and-simple-API-for-Reflection-i). 它使反射速度提高100倍(我指的是最字面的“字面”一词,而不是经常被误用的比喻)

我的代码现在可以加载数据并将数据放入我的业务对象,就像SQLServerManagementStudio在表上执行select*一样快


我刚刚运行了这段代码,检查表中的任何数据类型,并使用适当的Get方法:

        foreach (var p in obj.Properties)
        {
            object value;
            var i = fieldNumbers[p.Alias];

            if (p.Type == "System.Nullable`1[System.Int16]") value = dr.GetSqlInt16(i);
            else if (p.Type == "System.Nullable`1[System.Int32]") value = dr.GetSqlInt32(i);
            else if (p.Type == "System.Nullable`1[System.Decimal]") value = dr.GetSqlDecimal(i);
            else if (p.Type == "System.Nullable`1[System.Boolean]") value = dr.GetSqlBoolean(i);
            else if (p.Type == "System.String") value = dr.GetSqlString(i);
            else if (p.Type == "System.Nullable`1[System.DateTime]") value = dr.GetSqlDateTime(i);
        }
这是:

            foreach (var p in obj.Properties)
            {
                object value;
                var i = fieldNumbers[p.Alias];
                value = dr[i];
            }
而第二个始终表现得更快。我对此感到惊讶,但这似乎是真的。有没有人能告诉我,我是否忽略了一些东西,因为我看到一些人声称使用GetXXX方法的性能更好。我将此作为一个整体进行计时,并对单个检索操作进行计时。我真的刚刚揭穿了一个神话吗

编辑:在测试了一些之后,我发现了一些问题

第一-使用get方法将值返回到强类型变量中稍微快一点(对于我运行的测试来说大约是8%),我在没有上面所有多余代码的情况下对其进行了测试,因此没有调度或类似的操作。。。只是苹果对苹果

但是,请注意,我使用的是GetSqlXXX函数,而不是GetXXX函数。这是因为后者不能用于空值。但是,前者返回的类型是SqlInt32而不是int?。我的字段不是SqlXXX,它们是简单的可为空类型,比如int?。我认为大多数人都会遇到这种情况,这意味着除非您想在整个代码中开始使用SqlTypes,否则无法真正提高类型化方法的速度

其次,我注意到检索空值的速度似乎比您通常预期的要慢。。。当然,这只是我的看法

编辑2:仅针对Doug McClean和Theevillpenguin,我按如下方式对分支进行“仅”计时:

        Stopwatch sw = new Stopwatch();
        long time = 0;

        while (dr.Read())
        {
            var obj = new O();
            obj.Initializing = true;


            sw.Restart();            
            foreach (var p in obj.Properties)
            {
                if (p.Type == "System.Nullable`1[System.Int16]") continue;
                else if (p.Type == "System.Nullable`1[System.Int32]") continue;
                else if (p.Type == "System.Nullable`1[System.Decimal]") continue;
                else if (p.Type == "System.Nullable`1[System.Boolean]") continue;
                else if (p.Type == "System.String") continue;
            }
            time += sw.ElapsedTicks;
        }
        sw.Stop();
        MessageBox.Show(time.ToString());
我不得不在这里留下一些不特定于分支的行,但是你可以看到,我只是把分支周围的时间加起来。起初,我是在毫秒内完成的,结果(大约60k条记录)是1。很明显,每个周期都不到一毫秒,所以我切换到滴答声,结果是466472,不到1毫秒的一半(除非我把小数点弄错了……如果我不在那里,请有人纠正我)。那么分支有多贵呢?不是


实际上,这些结果看起来非常小,所以如果我在测试中犯了错误,请有人纠正我,但无论哪种方式分支都是最便宜的事情之一。

我怀疑,尽管我还没有进行基准测试,如果你静态地知道与每个
I
相关联的内容的类型,与完全动态索引器语法相比,
GetXXX(i)
方法可能具有性能优势


另一方面,通过调度我不希望优于内置动态版本的类型来滚动您自己的动态版本,因此我对给出的示例并不感到惊讶。

这一切都取决于ADO提供程序,这个答案涉及SQL Server ADO.NET提供程序,也称为
SqlClient

看看你的基准测试,它看起来是无效的。特别是在混合中添加了一组字符串比较

对于有效的微基准测试,
GetXYZ
稍微快一点,因为
GetValue
的开销稍大,特别是:

  • GetValue
    将内容导入内部
    SqlBuffer.Value
    中,这是一个简单的case语句,可以分派到相同的属性
    GetXYZ
    分派

  • GetValue
    调用
    SqlStatistics.StartTimer
    ,而
    GetXYZ
    调用不调用

  • 您可能会烘焙一个稍微快一点的
    GetValue()
    实现,我怀疑这是否值得

    以下微观基准测试演示了性能差异:

    // include Dapper from nuget
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Data.SqlClient;
    using Dapper;
    using System.Diagnostics;
    
    namespace ConsoleApplication16
    {
        class Program
        {
            static void Main(string[] args)
            {
                var cnn = new SqlConnection("Data Source=.;Initial Catalog=tempdb;Integrated Security=True");
                cnn.Open();
    
                cnn.Execute("create table #t(num int, str nvarchar(50))");
    
                // 10 k records
                cnn.Execute("insert #t values (@num, @str)", 
                    Enumerable.Range(1, 10000).Select(i => new { num = i, str = Guid.NewGuid().ToString() }));
    
                Stopwatch sw;
    
                SqlCommand cmd = new SqlCommand("select * from #t");
                cmd.Connection = cnn;
    
                for (int i = 0; i < 10; i++)
                {
                    sw = Stopwatch.StartNew();
                    using (var reader = cmd.ExecuteReader())
                    {
                        int num;
                        string str;
                        while (reader.Read())
                        {
                            num = reader.GetInt32(0);
                            str = reader.GetString(1);
                        }
                    }
                    Console.WriteLine("GetXYZ {0}", sw.ElapsedTicks);
    
                    sw = Stopwatch.StartNew();
                    using (var reader = cmd.ExecuteReader())
                    {
                        int num;
                        string str;
                        while (reader.Read())
                        {
                            num = (int)reader.GetValue(0);
                            str = (string)reader.GetValue(1);
                        }
                    }
                    Console.WriteLine("GetValue {0}", sw.ElapsedTicks);
                }
    
                Console.ReadKey();
            }
        }
    }
    
    //包括nuget的Dapper
    使用制度;
    使用System.Collections.Generic;
    使用System.Linq;
    使用系统文本;
    使用System.Data.SqlClient;
    使用整洁;
    使用系统诊断;
    命名空间控制台应用程序16
    {
    班级计划
    {
    静态void Main(字符串[]参数)
    {
    var cnn=new-SqlConnection(“数据源=;初始目录=tempdb;集成安全性=True”);
    cnn.Open();
    执行(“创建表#t(num int,str nvarchar(50))”;
    //10K记录
    Execute(“插入#t值(@num,@str)”,
    范围(11000)。选择(i=>new{num=i,str=Guid.NewGuid().ToString()});
    秒表开关;
    SqlCommand cmd=newsqlcommand(“选择*from#t”);
    cmd.Connection=cnn;
    对于(int i=0;i<10;i++)
    {
    sw=秒表。开始新();
    使用(var reader=cmd.ExecuteReader())
    {
    int-num;
    字符串str;
    while(reader.Read())
    {
    num=reader.GetInt32(0);
    str=reader.GetString(1);
    }
    }
    Console.WriteLine(“GetXYZ{0}”,sw.ElapsedTicks);
    sw=秒表。开始新();
    使用(var reader=cmd.ExecuteReader())
    {
    int-num;
    字符串str;
    while(reader.Read())
    {
    num=(int)reader.GetValue(0);
    str=(string)reader.GetValue(1);
    }
    }
    GetXYZ 25094
    GetValue 27877
    GetXYZ 24226
    GetValue 25450
    ...
    GetXYZ 24029
    GetValue 26571