博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
CYQ.Data 轻量数据层之路 MDataTable 绑定性能优化之章(十一)
阅读量:7093 次
发布时间:2019-06-28

本文共 9342 字,大约阅读时间需要 31 分钟。

hot3.png

昨天jyk进群后,用Microsoft Application Center Test 对CYQ.Data 框架进行进行了一下压力测试

然后截了几张图上来,只有纯图如下:

1:使用了框架:sql 2000的分页存储过程[临时表分的页]:

2:把存储过程直接换成select语句:

3:他的框架测试结果:

4:这是测试结果了。

以下是说明:

1、DataTable :714次/秒
2、MDataTable:559 次/秒 (简单存储过程)
3、MDataTable:500 次/秒 (完整存储过程)

 

 

简单的说就是自定义的MDataTable性能不够理想,比DataTable还差,那还自定义干什么?直接使用DataTable不就了事了?

 

当然了,我当时的第一想法,MDataTable是不应该比DataTable慢的,算下体积,关联的类,都比DataTable简化这么多,怎么可能比DataTable性能差呢?

还记得我在发布: 时,在最下面的留言中,有一个测试

示例1:测试代码如下:

05233653_xu8W.gif 测试示例1
        DateTime start 
=
 DateTime.Now;
        
for
 (
int
 i 
=
 
0
; i 
<
 
10000
; i
++
)
        {
            MDataTable table 
=
 
new
 MDataTable(
"
myTableName
"
);
            table.Columns.Add(
"
Url
"
, SqlDbType.NVarChar);
            table.Columns.Add(
"
Name
"
, SqlDbType.NVarChar);
            MDataRow mdr 
=
 table.NewRow();
            mdr[
0
].Value 
=
 
"
http://cyq1162.cnblogs.com/
"
;
            mdr[
1
].Value 
=
 
"
路过秋天
"
;
            table.Rows.Add(mdr);
        }
        TimeSpan ts 
=
 DateTime.Now 
-
 start;
        Response.Write(
"
MDataTable:
"
+
ts.Ticks.ToString() 
+
 
"
<br>
"
);
        DateTime start2 
=
 DateTime.Now;
        
for
 (
int
 j 
=
 
0
; j 
<
 
10000
; j
++
)
        {
            DataTable table 
=
 
new
 DataTable(
"
myTableName
"
);
            table.Columns.Add(
"
Url
"
);
            table.Columns.Add(
"
Name
"
);
            DataRow mdr 
=
 table.NewRow();
            mdr[
0
=
 
"
http://cyq1162.cnblogs.com/
"
;
            mdr[
1
=
 
"
路过秋天
"
;
            table.Rows.Add(mdr);
        }
        TimeSpan ts2 
=
 DateTime.Now 
-
 start2;
        Response.Write(
"
 DataTable:
"
+
ts2.Ticks.ToString());

 

 

得出的结果是:

1:MDataTable:156250
2: DataTable:1562500
结论:
自定义的MDataTable比DataTable速度快10倍。

 

 

不过就在回头间,我想到了,速度慢的原因可能在其实现的绑定机制上。

于是,我在上面的测试代码中,从界面拖了两个控件,分别为之绑定控件测试:

示例2:测试代码,看两句加红标注:

05233653_xu8W.gif 测试示例2
        DateTime start 
=
 DateTime.Now;
        
for
 (
int
 i 
=
 
0
; i 
<
 
10000
; i
++
)
        {
            MDataTable table 
=
 
new
 MDataTable(
"
myTableName
"
);
            table.Columns.Add(
"
Url
"
, SqlDbType.NVarChar);
            table.Columns.Add(
"
Name
"
, SqlDbType.NVarChar);
            MDataRow mdr 
=
 table.NewRow();
            mdr[
0
].Value 
=
 
"
http://cyq1162.cnblogs.com/
"
;
            mdr[
1
].Value 
=
 
null
;
            table.Rows.Add(mdr);
            
gv1.DataSource =
 table;
            gv1.DataBind();
        }
        TimeSpan ts 
=
 DateTime.Now 
-
 start;
        Response.Write(
"
MDataTable:
"
+
ts.Ticks.ToString() 
+
 
"
<br>
"
);
        DateTime start2 
=
 DateTime.Now;
        
for
 (
int
 j 
=
 
0
; j 
<
 
10000
; j
++
)
        {
            DataTable table 
=
 
new
 DataTable(
"
myTableName
"
);
            table.Columns.Add(
"
Url
"
);
            table.Columns.Add(
"
Name
"
);
            DataRow mdr 
=
 table.NewRow();
            mdr[
0
=
 
"
http://cyq1162.cnblogs.com/
"
;
            mdr[
1
=
 
null
;
            table.Rows.Add(mdr);
            
gv2.DataSource 
=
 
table;
            
gv2.DataBind();
        }
        TimeSpan ts2 
=
 DateTime.Now 
-
 start2;
        Response.Write(
"
 DataTable:
"
+
ts2.Ticks.ToString());

 

 

得出的结果是:

1:MDataTable:17968750
2:DataTable: 10312500
结论:
自定义的MDataTable在绑定时比DataTable慢了0.7倍左右。

 

虽然得之绑定时比DataTable慢,但具体慢的原因,还是得找出来的。

 

原因分析一:数据查询速度

第一步测试一下:返回一个MDataTable是不是比返回一个DataTable慢。

同时也怀疑是不是从SqlDataReader隐藏转换到MDataTable时,造成的性能差。

于是把框架简单修改一下,开放了SQLHelper,开放返回DataTable的方法,接着产生了以下的测试代码:

示例3:

05233653_xu8W.gif 测试示例3
        
string
 sql 
=
 
"
select * from Users
"
;
        SQLHelper helper 
=
 
new
 SQLHelper();
        DateTime start2 
=
 DateTime.Now;
        
for
 (
int
 j 
=
 
0
; j 
<
 
1000
; j
++
)
        {
            MDataTable mTable 
=
 helper.ExeDataReader(sql, 
false
);
        }
        TimeSpan ts2 
=
 DateTime.Now 
-
 start2;
        Response.Write(
"
MDataTable:
"
 
+
 ts2.Ticks.ToString());
        DateTime start 
=
 DateTime.Now;
        
for
 (
int
 i 
=
 
0
; i 
<
 
1000
; i
++
)
        {
            DataTable table 
=
 helper.ExeDataTable(sql, 
false
);
        }
        TimeSpan ts 
=
 DateTime.Now 
-
 start;
        Response.Write(
"
DataTable:
"
 
+
 ts.Ticks.ToString()
+
"
<br>
"
);
        helper.Dispose();

 

 

测试结果:

1:MDataTable:1875000
2: DataTable:2656250
结论:
直接回返自定义的MDataTable比DataTable 快0.N倍。

 

 

从以上结果看出,无论在实例化,还是在查询速度上,自定义的MDataTable都是优于DataTable的。可是结果在绑定时反而变慢了,于是继续分析。

 

原因分析二:绑定机制

第一步,从实现绑定机制上走,首先自定义的MDataTable走的绑定机制源自DataReader方式,和DataTable不一样,于是产生第一个想法:

用源生的SqlDataReader绑定和DataTable绑定比较,测试代码:

示例4:

05233653_xu8W.gif 测试示例4
        
string
 sql 
=
 
"
select * from Users
"
;
        DateTime start 
=
 DateTime.Now;
        
for
 (
int
 i 
=
 
0
; i 
<
 
1000
; i
++
)
        {
            SQLHelper  helper 
=
 
new
 SQLHelper();
            DataTable table 
=
 helper.ExeDataTable(sql, 
false
);
            gv1.DataSource 
=
 table;
            gv1.DataBind();
            helper.Dispose();
        }
        TimeSpan ts 
=
 DateTime.Now 
-
 start;
        Response.Write(
"
DataTable:
"
 
+
 ts.Ticks.ToString() 
+
 
"
<br>
"
);
        DateTime start2 
=
 DateTime.Now;
        
for
 (
int
 j 
=
 
0
; j 
<
 
1000
; j
++
)
        {
            SQLHelper helper 
=
 
new
 SQLHelper();
            SqlDataReader reader 
=
 helper.ExeDataReader(sql, 
false
);
            gv2.DataSource 
=
 reader;
            gv2.DataBind();
            reader.Close();
            helper.Dispose();
        }
        TimeSpan ts2 
=
 DateTime.Now 
-
 start2;
        Response.Write(
"
SqlDataReader:
"
 
+
 ts2.Ticks.ToString());

 

 

测试结果:

1
:     DataTable:
10156250
2
: SqlDataReader:
8437500
结论是:
用SqlDataReader绑定比DataTable绑定快一些。

 

 

于是,最后得出结论是:还真是我绑定代码写的有问题,导致性能比DataTable差了一点

 

三:代码优化之章

既然代码写的不够好,就得优化了。于是接着研究DataReader的绑定接口的实现,发现有这么一些返回代码:

05233653_xu8W.gif
    
public
 
override
 
short
 GetInt16(
int
 i)
    {
        
this
.ReadColumn(i);
        
return
 
this
._data[i].Int16;
    }
    
public
 
override
 
int
 GetInt32(
int
 i)
    {
        
this
.ReadColumn(i);
        
return
 
this
._data[i].Int32;
    }
    
public
 
override
 
long
 GetInt64(
int
 i)
    {
        
this
.ReadColumn(i);
        
return
 
this
._data[i].Int64;
    }

瞬间给了我一些启发,那就是模拟相似的实现方式了:

新建了一个类CellValueType:

并增加所有类型属性,一开始是prop的一个一个敲,累死人了。

05233653_xu8W.gif
internal
 
class
 CellValueType
{
        
public
 
int
 Int;
        
public
 
string
 String;
        
public
 
bool
 Bool;
        
public
 
byte
 Byte;
        
public
 
char
 Char;
        
public
 
long
 Long;
        
public
 DateTime DateTime;
        
public
 
decimal
 Decimal;
        
public
 
double
 Double;
        
public
 
float
 Float;
        
public
 Type Type;
        
public
 Guid Guid;
        
public
 Int16 Int16;
        
public
 Int32 Int32;
        
public
 Int64 Int64;
        
public
 
short
 Short;
}

 

接着增加方法,为属性设置值:手动敲这些代码,你说累不累人。

 

05233653_xu8W.gif Set 方法
        
internal
 
void
 Set(
object
 value)
        {
            
this
.Type 
=
 value.GetType();
            
switch
 (Type.Name.ToLower())
            {
                
case
 
"
char
"
:
                    
this
.Char 
=
 (
char
)value;
                    
break
;
                
case
 
"
boolean
"
:
                    
this
.Bool 
=
 (
bool
)value;
                    
break
;
                
case
 
"
byte
"
:
                    
this
.Byte 
=
 (
byte
)value;
                    
break
;
                
case
 
"
datetime
"
:
                    
this
.DateTime 
=
 (DateTime)value;
                    
break
;
                
case
 
"
decimal
"
:
                    
this
.Decimal 
=
 (
decimal
)value;
                    
break
;
                
case
 
"
double
"
:
                    
this
.Double 
=
 (
double
)value;
                    
break
;
                
case
 
"
guid
"
:
                    
this
.Guid 
=
 (Guid)value;
                    
break
;
                
case
 
"
int16
"
:
                
case
 
"
uint16
"
:
                    
this
.Int16 
=
 (Int16)value;
                    
break
;
                
case
 
"
int
"
:
                    
this
.Int 
=
 (
int
)value;
                    
break
;
                
case
 
"
int32
"
:
                
case
 
"
uint32
"
:
                    
this
.Int32 
=
 (Int32)value;
                    
break
;
                
case
 
"
int64
"
:
                
case
 
"
uint64
"
:
                    
this
.Int64 
=
 (Int64)value;
                    
break
;
                
case
 
"
float
"
:
                
case
 
"
single
"
:
                    
this
.Float 
=
 (
float
)value;
                    
break
;
                
case
 
"
string
"
:
                    
this
.String 
=
 (
string
)value;
                    
break
;
                
case
 
"
long
"
:
                    
this
.Long 
=
 (
long
)value;
                    
break
;
                
case
 
"
short
"
:
                    
this
.Short 
=
 (
short
)value;
                    
break
;
            }
        }

 

 

接着在单元格类里增加该类,并在为单元格值赋值时调用此方法:

05233653_xu8W.gif
public
 
class
 MDataCell
{
        
//
...能省就省...
        
internal
 CellValueType _CellValueType;
       
//
...能省就省...
        
#region
 初始化
        
private
 
void
 Init(CellStruct dataStruct, 
object
 value)
        {
            _CellValueType 
=
 
new
 CellValueType();
           
//
...能省就省...
        }
      
//
...能省就省...
        
public
 
object
 Value
        {
            
get
            {
                
return
 _CellValue.Value;
            }
            
set
            {
                
//
...能省就省...
                _CellValueType.Set(value);
            }
         }
}

 

一切就绪,于是回到MDataTable实现接口的实现之处,写下和DataReader相似的代码:

05233653_xu8W.gif
        
public
 
float
 GetFloat(
int
 i)
        {
            
return
 _Mdr[_Ptr][i]._CellValueType.Float;
        }
        
public
 Guid GetGuid(
int
 i)
        {
            
return
 _Mdr[_Ptr][i]._CellValueType.Guid;
        }
        
public
 
short
 GetInt16(
int
 i)
        {
            
return
 _Mdr[_Ptr][i]._CellValueType.Short;
        }

 

改完之后,马上测试结果:

用的上面的示例2:

测试结果:

1
: MDataTable:
8906250
2
: DataTable:
11093750
结论:
MDataTable在绑定时性能终于上去了,超越DataTable了

 

接着又用示例1:

测试结果:

1
:MDataTable:
312500
2
:DataTable:
1718750
 
结论是:
原来比DataTable快10倍的差距,纯减到5倍多一点。

 

 

按理就这么算了,绑定快一点,实例化时不要那么快,也是可以接受的。

不过,还是要抓个问底,究竟是哪句代码影响了性能。

于是继续研究,采取代码注释,步步换回原来的代码测试,终于把性能杀手抓出来了:

05233653_xu8W.gif
        
public
 
string
 GetDataTypeName(
int
 i)
        {
            
return
 DataType.GetDbType(_Mdr[_Ptr][i]._CellStruct.SqlType.ToString()).ToString();
        }
        
public
 Type GetFieldType(
int
 i)
        {
            
return
 Type.GetType(
"
System.
"
 
+
 GetDataTypeName(i));
        }

 

就是这两个家伙了,上面那个家伙还行,下面那个家伙就大大的不行了,Type.GetType方法,大伙自己拈着点用了。

 

既然抓到了真胸,那我原来的模仿存在的意义好像就不是那么明显了,只要能优化这里,那些模仿可以去掉了,同时又可以恢复原来10倍的性能差距。

当然了,同时我发现通过Value.GetType是有问题的,如果绑定的值是Null,虽然可以判断了事,不过每次对Value取值也不太稳。

于是新生方法又产生了:

为单元结构添加多一个属性,换掉整个CellValueType类。

在构造头部结构时,完成对Type的初始设置,如下:

05233653_xu8W.gif
  
///
 
<summary>
    
///
 单元结构属性
    
///
 
</summary>
    
public
 
class
 CellStruct
    {
       
//
...能省则省...
        
internal
 Type ValueType;
        
#region
 构造函数
        
public
 CellStruct(
string
 columnName, System.Data.SqlDbType sqlType, 
bool
 isReadOnly, 
bool
 isCanNull, 
int
 maxSize, ParameterDirection paraDirection)
        {
            
//
...能省则省...
            ValueType 
=
 DataType.GetType(sqlType);
        }
        
#endregion
    }

 

同时DataType增加一内部方法用于从SqlType转到Type:[又是手动敲的,累死人罗]

05233653_xu8W.gif GetType 方法
 
internal
 
static
 Type GetType(SqlDbType sqlType)
        {
            
switch
 (sqlType)
            {
                
case
 SqlDbType.BigInt:
                    
return
 
typeof
(Int64);
                
case
 SqlDbType.Binary:
                
case
 SqlDbType.Image:
                
case
 SqlDbType.Timestamp:
                
case
 SqlDbType.VarBinary:
                    
return
 
typeof
(Byte);
                
case
 SqlDbType.Bit:
                    
return
 
typeof
(Boolean);
                
case
 SqlDbType.Text:
                
case
 SqlDbType.Char:
                
case
 SqlDbType.NChar:
                
case
 SqlDbType.NText:
                
case
 SqlDbType.NVarChar:
                
case
 SqlDbType.VarChar:
                    
return
 
typeof
(String);
                
case
 SqlDbType.SmallDateTime:
                
case
 SqlDbType.DateTimeOffset:
                 
case
   SqlDbType.DateTime2:
                
case
 SqlDbType.DateTime:
                
case
 SqlDbType.Date:
                    
return
 
typeof
(DateTime);
                
case
 SqlDbType.Money:
                
case
 SqlDbType.Decimal:
                
case
 SqlDbType.SmallMoney:
                    
return
 
typeof
(Decimal);
                
case
 SqlDbType.Float:
                    
return
 
typeof
(
double
);
                
case
 SqlDbType.Int:
                    
return
 
typeof
(
int
);
                
case
 SqlDbType.Real:
                    
return
 
typeof
(Single);
                
case
 SqlDbType.TinyInt:
                
case
 SqlDbType.SmallInt:
                    
return
 
typeof
(Int16);
                
case
 SqlDbType.UniqueIdentifier:
                    
return
 
typeof
(Guid);
                
default
:
                    
return
 
typeof
(
object
);
            }
        }

 

OK,至此,相关的返回取结构体的Type属性就行了,最后看测试结果:

示例1测试结果:

1:MDataTable:156250
2:DataTable: 1718750 
结论:
10倍的差距速度回来了。

 

 

对示例2测试结果:

1:MDataTable:8750000
2:DataTable:11093750 
结论:
速度上仍超越了DataTable,虽然没超越多少。不过比起之前慢了0.7倍左右到现在反超回来,是一大提升了。

 

 

 

最后结案陈词:

 

继续欢迎光大群众对本框架的使用与测试,本框架将与时俱进,尽情做到让使用者放心,省心。
欢迎留言讨论。

 

 

转载于:https://my.oschina.net/secyaher/blog/274298

你可能感兴趣的文章
关于display aspect ratio
查看>>
CentOS7 网卡启动失败解决方案
查看>>
BroadcastReceiver的两种注册方式(静态注册和动态注册)
查看>>
主机win7与虚拟linux无法ssh问题解析
查看>>
8.1.3 链路状态数据库
查看>>
I/O重定向和管道——《Unix/Linux编程实践教程》读书笔记(第10章)
查看>>
华章1-2月份新书简介(2018年)
查看>>
PreparedStatement的用法
查看>>
For多重循环 break continue
查看>>
Spring源码解析:Bean实例的创建与初始化
查看>>
我的友情链接
查看>>
百度是如何给每个人免费提供2TB存储空间的?
查看>>
php7.2.6源码编译安装
查看>>
Titanium Terminal 不好使的解决办法
查看>>
我的友情链接
查看>>
BaseRecyclerViewAdapterHelper开源项目之点击事件源码学习
查看>>
JAVA解析JSON大全
查看>>
Java基础学习总结(23)——GUI编程
查看>>
让App的运行速度与响应速度趋于一流(iOS)
查看>>
大型网站技术架构(八)网站的安全架构
查看>>