zoukankan      html  css  js  c++  java
  • select * from table 时间长

        优化中发现一个存储过程执行20秒通过profiler 抓取发现时间主要消耗在一个select * from 表,那么问题来了select几万数据竟然花了将近20秒?

        问题排查清了程序前端使用了datareader获取数据,那么datareader对数据库有什么影响呢?下面来做个实验测试一下。首先我们创建测试表并插入200条数据。

        

    1 CREATE TABLE [dbo].[table_2](
    2     [a] [int] NULL,
    3     [b] [datetime] NULL,
    4     [c] [uniqueidentifier] NOT NULL
    5 )
    6 
    7 insert into [table_2]
    8 select 1,getdate(),newid()
    9 go 200

    编写一段简单的C#小程序,使用datareader读取一个select * from table 在datareader的循环中我们设置线程等待50毫秒。System.Threading.Thread.Sleep(50);

        

    protected void Button1_Click(object sender, EventArgs e)
            {
    
    
                //SqlCommand sqlCmd = new SqlCommand("p_datareader_test", con);
                //sqlCmd.Connection = con;
                //sqlCmd.CommandType = CommandType.StoredProcedure;//设置调用的类型为存储过程  
    
                //SqlParameter sqlParme = new SqlParameter();
                //sqlParme = sqlCmd.Parameters.Add("@p", SqlDbType.Int);
                //sqlParme.Direction = ParameterDirection.Input;
                //sqlParme.Value = 0;
    
                //SqlDataReader reader = sqlCmd.ExecuteReader();
    
                SqlConnection con = new SqlConnection();
                con.ConnectionString = "server=vpc-new3;database=replication;uid=sa;pwd=sa_123456";
                DataTable dt = new DataTable();
    
    
                //SQL直接查询测试-------------------------------
                con.Open();
                SqlCommand com = new SqlCommand();
                com.Connection = con;
                com.CommandType = CommandType.Text;
                com.CommandText = "select * from table_2";
    
    
                SqlDataReader reader = com.ExecuteReader();
    
                DataRow dtr  = dt.NewRow () ;
    
                try
                {
                    DataTable objDataTable = new DataTable();
                    int intFieldCount = reader.FieldCount;
                    for (int intCounter = 0; intCounter < intFieldCount; ++intCounter)
                    {
                        objDataTable.Columns.Add(reader.GetName(intCounter), reader.GetFieldType(intCounter));
                    }
                    objDataTable.BeginLoadData();
    
                    object[] objValues = new object[intFieldCount];
                    while (reader.Read())
                    {
                        //系统等待
                        System.Threading.Thread.Sleep(50);
                        reader.GetValues(objValues);
                        objDataTable.LoadDataRow(objValues, true);
                    }
                    reader.Close();
                    objDataTable.EndLoadData();
    
                    GV .DataSource = objDataTable;
                    GV.DataBind();
                    
                }
                catch (Exception ex)
                {
                    throw new Exception("转换出错!", ex);
                }
                reader.Close();
                con.Close();
    
            }

        下面来测试执行一下:

        点击按钮出发btnclick

      

        

        执行时间0毫秒?竟然不像想象中的时间会长? 这是为什么呢?

        

        测试继续! 我们加大数据,继续添加200条。

        

    insert into [table_2]
    select 1,getdate(),newid()
    go 200

        

        测试效果一样0毫秒。

        继续增加200 条 目前数据600条

        

        看一下效果:

        

        效果神奇的出现了 600条记录的查询需要12秒!!

        我们再一次执行观察一下竟然12秒才执行完肯定会有等待!

        

    select wait_type,brt.text from sys.dm_exec_requests br 
             OUTER APPLY sys.dm_exec_sql_text(br.sql_handle) AS brt
             where brt.text like '%table_2%'

        

        没错就是他 传说中的ASYNE_NETWORK_IO 

        

        

        疑问:按照之前的理解datareader 一次只是读取一条记录...那么为什么我400条记录的时候就不会出现等待呢?

        想到了发送的网络包大小,mssql默认为4096

        

        那么我们继续用200条数据测试这次加大表的长度

        

    drop table table_2
    
    CREATE TABLE [dbo].[table_2](
        [a] [int] NULL,
        [b] [datetime] NULL,
        [c] [uniqueidentifier] NOT NULL,
        d char(4000)
    )
    
    insert into [table_2]
    select 1,getdate(),newid(),'test'
    go 200

        再次测试执行观察效果

        

        好吧我猜对了....

        后续用dataset接收返回结果就不会出现上述问题,所以如网上所说datareader接收结果集使用要注意接收结果后要避免在循环中有大量的耗时处理。

  • 相关阅读:
    .net测试篇之Moq行为配置
    .net测试篇之Moq框架简单使用
    .net测试篇之测试神器Autofixture在几个复杂场景下的使用示例以及与Moq结合
    .net测试篇之测试神器Autofixture Generator使用与自定义builder
    .net测试篇之测试神器Autofixture基本配置一
    .net测试篇之单元测试/集成测试神器Autofixture
    .netcore持续集成测试篇之web项目验收测试
    .netcore持续集成测试篇之 .net core 2.1项目集成测试
    .netcore持续集成测试篇之MVC层单元测试
    .netcore持续集成测试篇之测试方法改造
  • 原文地址:https://www.cnblogs.com/double-K/p/4979265.html
Copyright © 2011-2022 走看看