SqlDataReader访问效率小探

来源:互联网 发布:淘宝网发布宝贝教程 编辑:程序博客网 时间:2024/05/18 03:16

 

SqlDataReader是面向连接的一个数据访问对象,是一个轻量级的、功能较弱的访问对象。区别于SqlDataAdapterDataSetSqlDataAdapter在从数据库中读取数据的时候,通过Fill方法把结果集填充到DataSet里,此时如果与数据库断开了,照样可以访问DataSet里的数据。对于SqlDataReader对象,因为它是面向连接的,每读取一条记录都必须实时的与数据库交互,读取一条,处理完后再到数据库里再取出一条记录来。若数据库断了,数据也就读不出来了。因为它是一条条的从数据库中读取结果集,而且是按照一定顺序读取的,读完了以后若要再次得到一样的结果集,必须重构SqlDataReader对象,然后在通过while语句来读取数据。(怎么使用while来读取数据及其其它相关知识这里不再赘述,可以参考msdnhttp://msdn.microsoft.com/zh-cn/library/system.data.sqlclient.sqldatareader(v=vs.80).aspx#Y800)。

         在过去的项目开发中,我们经常通过SqlDataReader对象的索引器来获取数据,如要得到列名为“SalesOrderDetailID”的记录,会使用dr[“SalesOrderDetailID”]来访问其值。当然我们也可以通过dr[0]来访问,其中0表示的是列的序号,如写了个查询语句:SELECT [SalesOrderDetailID],[ OrderQty] FROM[AdventureWorks].[Sales].[SalesOrderDetail]。其中dr[0]对应的是SalesOrderDetailID dr[1]对应的是OrderQty。还有第三种访问方式,通过GetValue方法访问,如dr.GetValue(0),其中0表示列的序号,同样还有Get+类型方法访问,如dr.GetInt32(0)。这时候问题出现了,四种访问方式一样吗,其效率如何?因此写了个小程序测试了下,先取样100,然后得出平均执行时间。数据库选择微软sqlserver里提供的示例数据库AdventureWorks,表使用SalesOrderDetail表,因为这张表中的记录条数>10万条,测试数据会比较准确。代码如下:

class Program

    {

        static void Main(string[]args)

        {

            stringsource=@"server=(local)/SQLSERVER2005;integratedsecurity=SSPI;database=AdventureWorks";

            floatsum=0;

            for(int i = 0; i < 100; i++)

            {

                try

                {

                    using(SqlConnection conn = new SqlConnection(source))

                    {

                        conn.Open();

 

                        SqlCommand cmd = new SqlCommand("SELECT[SalesOrderDetailID] FROM [AdventureWorks].[Sales].[SalesOrderDetail]",conn);

                        System.Diagnostics.Stopwatch sw = newSystem.Diagnostics.Stopwatch();

                        sw.Start();

 

                        int o;

                        SqlDataReader dr = cmd.ExecuteReader();

                        while (dr.Read())

                        {

                            o = (int)dr["SalesOrderDetailID"];

                            //o = (int)dr[0];

                         //o = dr.GetInt32(0);

                        //o =(int)dr.GetValue(0);

                        }

                        dr.Close();

 

                        sw.Stop();

                        string tmp = string.Format("{0}.{1}", sw.Elapsed.Seconds,sw.Elapsed.Milliseconds);

                        sum += float.Parse(tmp);

                        Console.Write(tmp+" ");

                    }

                }

                catch(SqlException ex)

                {

                    Console.WriteLine(ex.Message);

                    Console.Read();

                }

            }

            Console.WriteLine("平均时间是:"+sum/100);

            Console.Read();

        }

    }

 

执行结果用如下:

 

dr["SalesOrderDetailID"]

dr[0]

dr.GetValue(0)

dr.GetInt32(0)

平均用时

0.6854

0.5416002

0.5030998

0.4504999

从上表可知访问效率:dr.GetInt32(0)>dr.GetValue(0) > dr[0]> dr["SalesOrderDetailID"]

以上是〉10万条记录的一个情况,如果记录数更多,4者的差别会更加的明显。这4者到底有什么样的区别呢?为什么会有性能差异呢?下面对其进行分析。

首先,针对于dr[0]dr["SalesOrderDetailID"]两种方式。dr[0]是通过数字访问,0指的就是列在结果集中的序号,通过列序号就可以取得到值。而dr["SalesOrderDetailID"]中索引器使用的是文本,针对文本索引,其内部机制是通过文本索引到结果集的模式内部去查找列序号,然后再使用列序号进行访问。其过程比数字索引多了一个文本匹配的过程,这就是两者差异所在。至于dr.GetValue (0),我们看看msdn的描述:

         为了获得最佳性能,SqlDataReader 会避免创建不必要的对象或复制不必要的数据。因此,对 GetValue 等方法的多次调用将返回对相同对象的引用。如果正在修改由 GetValue 等方法返回的对象的基础值,请使用警告。

故其性能是优于数字索引和文本索引的。对于dr.GetInt32(0)内部原理其实跟GeValue差不多,但是在程序中我们发现,前面三种访问方式再取到数据时,都必须进行拆箱操作,而装箱和拆箱操作对性能都有非常不利的影响,所以其优于其它3种方式。在表中我们也会发现,dr.GetInt32(0)> dr.GetValue(0)> dr[0]这三者用时比较相近,原因之一:dr[0]性能开销主要是在获取数据类型的时候,而dr.GetInt32则不用。

         其实4种访问方式各有千秋。对于数据索引有点好处在于可以避免把数据库字段暴露给应用程序。而对于文本索引则相反,字段暴露给应用程序后,程序员就不用去记那些晦涩的数字,对于程序代码也是一目了然,对代码的开发和维护都所有帮助。到底是用哪种访问方式更好?只能根据实际项目的需要去权衡。