在.Net中的部署和运行有一个现象就是:
.Net在部署后第一次运行时间要大大大于以后的运行时间。
因为.NET编译出来的全是中间语言。第一次运行的时候需要将中间语言编译成为机器语言。所以编译特别慢,如果某个模块常时间不用好像也是会慢一点。
我想除了以上的问题是不是还有优化的问题啊。
假定的系统是B/S结构的,比如缩小网页上的图片,改BMP格式为jpg格式,或者缩小图片质量,等等。还有就是硬件的升级,这个也许最见效果的方式了!增加内存十分重要。实在不成增加其他配置。比如换服务器等等。
.Net在部署后第一次运行时间要大大大于以后的运行时间。
因为.NET编译出来的全是中间语言。第一次运行的时候需要将中间语言编译成为机器语言。所以编译特别慢,如果某个模块常时间不用好像也是会慢一点。
我想除了以上的问题是不是还有优化的问题啊。
假定的系统是B/S结构的,比如缩小网页上的图片,改BMP格式为jpg格式,或者缩小图片质量,等等。还有就是硬件的升级,这个也许最见效果的方式了!增加内存十分重要。实在不成增加其他配置。比如换服务器等等。
解决方案 »
- 50分关于FreeTextBox插入图片问题
- C# 图像剪切 参数解释?
- 求“绑定水晶报表纵轴和横轴”代码
- 程序间共享变量 求解
- 使用serialport类,如何判断上位机已经停止向计算机发送数据?
- 使用SOCKET通信,出现问题。
- Object reference not set to an instance of an object.大侠们帮忙了. 顶者有分
- DataGrid下拉框问题?
- 请问C#中调用WindowsAPI, LPTSTR对应什么类型?
- 谁有<C#入门经典>这本书的电子版???
- 怎样用程序在桌面上建立一个文件的快捷方式?
- 请教一个简单问题,C#中如何使用 pen 画一条直线?!
2:差别的时间太离谱了!--〉
1。 如果有可能,使用.net中的SqlClient,会比OleDb那一套连接快许多
2。 如果有可能,不要使用IDataAdapter来Fill数据,采用IDataReader会快许多(数据量大的时候,尤其明显)
3。 再有就是要看看你的代码,你的Model1和Model2测出来的结果,悬殊有点大,最好,把逻辑、数据传输层、数据模块层服务器与数据库服务器分开,这样得到的结果,更真实些。
ADO.NET和数据库建立连接是要花时间的。
另外,在大数据量时,构建DataSet的时间和小数据量相比会很大
1:数据模块层在对于SQL Server数据库的时候肯定是用SqlClient,直连的时候也是。
2:IDataReader使用起来会有一些问题,在本系统中会有一些麻烦。
3:后来我分析Mode1与Mode2的差异,可能是这样。
在这个系统中为了效率及实际应用考虑,界面层与逻辑层(现在逻辑层与扩展层是绑在一起动的)之间的连接采用HTTP,其余各层之间用TCP连接,可能在本机用HTTP连接本机比较快一点。
-》SQL Server的连接效率比.Net的连接效率高
--》这个基本不可能
--》效率还要看里具体的code了,也不一定就是几层的问题
实际上这个系统已经做了很久了,从我一个人孤军奋战到现在一个4个人的小Team,已经做了大约快半年了。前期主要搭了个多层的架子,然后开始编写一些系统需要的必要控件和一些自有简易平台的开发,最近需要合拢,并做一些具体的测试优化工作,在网速不错的情况下效果还是可以的,只是前几天在测试网速极低情况下系统的速度的时候发现了一些问题。
但是测试所用的代码很简单,就是一个IDataAdapter填充一个数据集,只不过一个是本机,一个是多层而已。可能界面层与逻辑层之间的连接采用HTTP导致看起来SQL Server的连接效率比.Net的连接效率高吧。暂时跟具体代码应该不会有关联。
肯定是包括连接时间。
在SQL Server连接的时候用了连接池。
在DAL层获得连接的时候自己也构造了一个小小的“Object(XXXConnection)池”已经尽量在优化了。
现在明显就是TDS传输的问题。
你把数据访问层放到SQLSERVER那台机子当然就快啦~~。。
不知道你的测试方案时什么,这里面显然没有什么缓冲池的问题,select 一张表,一个connection,没有缓冲问题
你指的Direct 的连接是什么? 如果说打开个Query Analyzer ,当然他最快,数据不用封装,Connection 还是Open的。
请给出测试用例。
在实际情况中,一次取出8700笔的资料,显然是不合理的,效率的原则很重要的一个方面是lazy evalution, 只有需要的时候才去取,你不可能在一个显示屏中显示8700资料,就意味着没有这样的需求。
效率不是有什么工具的问题,效率是设计的问题,poor design 是效率的根源。我对你的测试用例和评估标准表示怀疑
结论是把数据访问层放到SQLSERVER那台机子会慢
例如第二个方案,慢在应用程序和业务层的地方。时间是8000,
第三个方案慢在数据层了SQL SERVER之间的地方,时间是6700那么是TDS转换成DataSet,然后DataSet序列化到XML再发送?
这些都是基本数据传输所必须的,你觉得用了dotnet后就慢了么?还有,这句“SQL Server的连接效率比.Net的连接效率高”到底是什么意思?
我们就分析8700条数据这种情况吧,效果明显些。
Direct: 这种情况下,网络传输的只是数据本身,然后客户端的.net将数据加载进入Dataset或DataReader。
Mode1: 这种模式是最惨烈的!!!数据传输层向客户端传回来的是数据模块层产生的Dataset或DataReader,Dataset是个超级大胖子,它的体积大约是原本8700条数据的80倍,网络传输量骤然增大。当然用DataReader会小一些。
Mode2:网络传输量与Direct类似,但客户端的.net构造8700条数据的DataSet本身也会进行大量运算。可以这样认为,本模式与Direct的耗时差额就是Dataset的构造所需时间。半年前,我也做过类似的测试,这是我的数据:
Typed Dataset Business Object
-----------------------------------------
1 | 1.02 0.01 1.02 0
20 | 1.02 0.02 1.03 0
300 | 1.03 0.12 1.02 0.05
4000 | 1.24 2.53 1.07 0.77
40000 | 5.56 78 3.27 9.59
---------------------------------------------
Recs D.A. N.T. D.A. N.T.Recs - 记录数;
D.A. - 数据访问(秒),DAL数据访问的耗时(包含生成Dataset或商务对象集合);
N.T.- 网络传输时间(秒),Dataset或商务对象集合从DAL到客户端的时间;
Typed Dataset - 类型化数据集;
Business Object - 数据商务对象;结论
造成多层应用反应时间滞后的两大原因:
1、使用类似Dataset等.net内置的数据管理对象,生成这些对象需要花费大量系统资源和你的时间。(如果你认为你有的是时间,那我还是建议你继续使用,为什么?使用它们可以减少大量额外的数据处理编程。)
2、在数据量庞大的分布式系统中,当DAL生成Dataset并向客户端返回时,你的噩梦开始了,(什么?你的客户每天都在做噩梦?你还尚存在这人世?佩服!换成我...我...汗),Dataset为了实现大量功能,它太庞大了,你的网络太累了。解决方案:
如果可能尽量不使用Dataset,使用DataReader会好许多。但更好的方法是使用定制的数据商务对象。使用数据商务对象是优化系统效率并与Typed Dataset有着相同功效的优秀方案。参考资料:
《VB.NET 事务处理高级编程》清华大学出版社
这个我觉的很容易解决了
1是数据分页,每次通过存储过程或是其他方式只返回所获取页面的记录,最多100多人,人眼也一一下看不过来
2是逐行更新,或是只发送更新行不了解你项目的情况,随便说说,供参考
这里面没有什么测试方案,严格说来这不算一个测试,连时间都是我自己估计的(没有多次平均),显然数据会分页读取,也显然在真正项目中不会一次读取8700条数据。我只是想知道时间差异的原因.
poor design 是效率的根源这句话很不好,从语法而言它是错误的,从效果而言我是很厌恶的,因为你已经知道只是select 一张表,一个connection,能有多少种实现模式?我能将它做得多Poor?何必要测试用例。
我想知道的就是williamjc() 的东西。感谢williamjc()。
-->Dataset是个超级大胖子,它的体积大约是原本8700条数据的80倍.
这句话最有用,但是80倍是不是有一点夸张啊?如果将一个DataSet保存为一个XML,也并不会增大如此多倍呀。而且在Direct模式中也会构造一次DataSet,显然时间不是很多。
使用定制的数据商务对象是一个好主义,不知道williamjc()兄能不能给点定制数据商务对象的一些建议或者是相关代码?
Common层有一个接口IDataBase,在每一层中传递。这个接口有若干简单数据方法,比如
GetDataSetBySql(string sql)就是其中的一个。
刚才我又测试了一下,直接通过数据层获得数据与通过逻辑层、数据层获得数据速度几乎是一样的,那么,这就应该是.NET Remoting序列化DataSet的原因了,这与构造填充DataSet还不一样,后者比前者要快得多。
不知道改用TCP+Binary的模式会不会好一些。
XML只是数据存储格式,Dataset是一个完整数据处理工具。我一直把它认为是工具。至于Dataset有多大,你可以做个例子啊!你可以在一个Form里添加一个SqlDataAdapter,然后右击它,选择预览数据,在数据预览窗口中单击“填充数据集”,看看吧你的数据集有多大?!
在Direct模式下,网络只传输数据本身,并不是Dataset,数据集在本地生成,你要看你的客户端硬件配置了。
代码比较多,我可以分部分贴出,不过你最好还是看一下我推荐的参考书,那里面讲得比较清楚。
{
//城市商务对象
[Serializable]
public __gc class BoCity : public BoBDbase
{
public:
BoCity(void);
BoCity(short nCity_id, String* sName, short nProvice_id, String* sProvince, String* sZipcode, String* sLDcode, String* sPYcode, String* sWBcode, String* sNote, Enumeration::Status eStatus);
~BoCity(void); __property short get_ProvinceID(){return m_nProvinceID;};
__property void set_ProvinceID(short value){m_nProvinceID = value;}; __property String* get_Zipcode(){return m_sZipcode;};
__property void set_Zipcode(String* value){if (NULL == value) m_sZipcode = String::Empty; else m_sZipcode = value;}; __property String* get_Province(){return m_sProvince;};
__property void set_Province(String* value){if (NULL == value) m_sProvince = String::Empty; else m_sProvince = value;}; __property String* get_LDcode(){return m_sLDcode;};
__property void set_LDcode(String* value){if (NULL == value) m_sLDcode = String::Empty; else m_sLDcode = value;}; private:
short m_nProvinceID;
String* m_sZipcode;
String* m_sProvince;
String* m_sLDcode;
}; [Serializable]
public __gc class BoCityCollection : public BDCollectionBase
{
public:
BoCityCollection();
~BoCityCollection(); __property BoCity* get_City(short n_id); _RESULT* Add(BoCity* pCityBo);
_RESULT* Add(short nCity_id, String* sName, short nProvice_id, String* sProvince,
String* sZipcode, String* sLDcode, String* sPYcode, String* sWBcode,
String* sNote, Enumeration::Status eStatus); _RESULT* Remove(short n_id);
_RESULT* Remove(BoCity* pCityBo); __property BoCity* get_Items(short Index);
};
}--------------------------------------------------------------------------
City.cppnamespace BusinessObjects
{
BoCity::BoCity(void) : BoBDbase()
{
Zipcode = String::Empty;
LDcode = String::Empty;
Province = String::Empty;
} BoCity::BoCity(short nCity_id, String* sName, short nProvice_id, String* sProvince, String* sZipcode, String* sLDcode, String* sPYcode, String* sWBcode, String* sNote, Enumeration::Status eStatus)
{
ID = nCity_id;
Name = sName;
ProvinceID = nProvice_id;
Province = sProvince;
Zipcode = sZipcode;
LDcode = sLDcode;
PYcode = sPYcode;
WBcode = sWBcode;
Note = sNote;
Status = eStatus;
} BoCity::~BoCity(void)
{
} BoCityCollection::BoCityCollection()
{
} BoCityCollection::~BoCityCollection()
{
} _RESULT* BoCityCollection::Add(BoCity* pCityBo)
{
_RESULT* p_scResult = new _RESULT(); try
{
CollectionBase::List->Add(pCityBo);
p_scResult->Completed = true;
}
catch (Exception* e)
{
Messager::GenerateExceptionMsg(e->Message, S"BoCityCollection::Add_I");
}
return p_scResult;
} _RESULT* BoCityCollection::Add(short nCity_id, String* sName, short nProvice_id, String* sProvince, String* sZipcode, String* sLDcode, String* sPYcode, String* sWBcode, String* sNote, Enumeration::Status eStatus)
{
_RESULT* p_scResult = new _RESULT(); try
{
BoCity* pCityBo = new BoCity(nCity_id, sName, nProvice_id, sProvince, sZipcode, sLDcode,sPYcode, sWBcode, sNote, eStatus);
CollectionBase::List->Add(pCityBo);
p_scResult->Completed = true;
}
catch (Exception* e)
{
Messager::GenerateExceptionMsg(e->Message, S"BoCityCollection::Add_II");
}
return p_scResult;
} _RESULT* BoCityCollection::Remove(BoCity* pCityBo)
{
_RESULT* p_scResult = new _RESULT(); try
{
CollectionBase::List->Remove(pCityBo);
p_scResult->Completed = true;
}
catch (Exception* e)
{
Messager::GenerateExceptionMsg(e->Message, S"BoCityCollection::Remove_I");
}
return p_scResult;
} _RESULT* BoCityCollection::Remove(short n_id)
{
_RESULT* p_scResult = new _RESULT(); try
{
CollectionBase::List->Remove(this->City[n_id]);
p_scResult->Completed = true;
}
catch (Exception* e)
{
Messager::GenerateExceptionMsg(e->Message, S"BoCityCollection::Remove_II");
}
return p_scResult;
} BoCity* BoCityCollection::get_Items(short Index)
{
BoCity* pCityBo;
pCityBo = dynamic_cast<BoCity*>(this->Item[Index]);
return pCityBo;
} BoCity* BoCityCollection::get_City(short n_id)
{
BoCity* pCityBo;
short i; for (i = 0; i < this->Count; i++)
{
if (Items[i]->ID == n_id)
{
pCityBo = this->Items[i];
break;
}
}
return pCityBo;
}
}
public __gc class BoCityCollection : public BDCollectionBase
改为
[Serializable]
public __gc class BoCityCollection : public CollectionBase[Serializable]
public __gc class BoCity : public BoBDbase
改为
[Serializable]
public __gc class BoCity
草草浏览了一下,这种东西有一个不好的地方,就是结构是固定的,不过也可以用继承自ColectionBase的东西模拟DataSet,就是编程起来比较麻烦,重要的是可读性太差了。
要是做这样一个东西在网络传输,然后在客户端以能够接受的速度转化为DataSet就
好了,嗯,可以试一试。