论坛
潜水/灌水快乐,沉淀知识,认识更多同行。
ToB圈子
加入IT圈,遇到更多同好之人。
朋友圈
看朋友圈动态,了解ToB世界。
ToB门户
了解全球最新的ToB事件
博客
Blog
排行榜
Ranklist
文库
业界最专业的IT文库,上传资料也可以赚钱
下载
分享
Share
导读
Guide
相册
Album
记录
Doing
搜索
本版
文章
帖子
ToB圈子
用户
免费入驻
产品入驻
解决方案入驻
公司入驻
案例入驻
登录
·
注册
只需一步,快速开始
账号登录
立即注册
找回密码
用户名
Email
自动登录
找回密码
密码
登录
立即注册
首页
找靠谱产品
找解决方案
找靠谱公司
找案例
找对的人
专家智库
悬赏任务
圈子
SAAS
IT评测·应用市场-qidao123.com
»
论坛
›
软件与程序人生
›
后端开发
›
.Net
›
都说Dapper性能好,突然就遇到个坑,还是个性能问题 ...
都说Dapper性能好,突然就遇到个坑,还是个性能问题
嚴華
论坛元老
|
2022-9-16 17:17:05
|
显示全部楼层
|
阅读模式
楼主
主题
1047
|
帖子
1047
|
积分
3141
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要
登录
才可以下载或查看,没有账号?
立即注册
x
本来闲来无事,准备看看Dapper扩展的源码学习学习其中的编程思想,同时整理一下自己代码的单元测试,为以后的进一步改进打下基础。
突然就发现问题了,源码也不看了,开始改代码,改了好久。
测试Dapper.LiteSql数据批量插入的时候,耗时20秒,感觉不正常,于是我测试了非Dapper版的LiteSql的批量插入,仅需100毫秒,速度差了200倍。
同样的数据库、同样的Npgsql.dll、同样的测试代码,产生的SQL和参数集合也是一样的,最后不得不怀疑Dapper。
引用Dapper的源码,修改调试之后,我决定提个PR。我之前没想过提PR,我想我也不是为了提PR而提PR,我也不想费时费力。
没想到提PR的过程很不顺利,原来提的PR需要单元测试全部通过才行。
我本机没环境不方便测,不过我发现提交申请之后,GitHub上立马自动编译测试,能看到哪些单元测试对了,哪些错了,真强大,真方便,原来大工程是这样的。
先是提交了一行代码,认为没有问题,结果被打了个叉。仔细一看才发现,原来是单元测试不通过。
改了又改,有几个存储过程相关的单元测试总是不通过。
都快要放弃了,后来想到是不是我定义的cleanNames变量随着DynamicParameters类的创建,又清空了,但cleanNames又不能定义成全局的。后来我加了几行代码。
一共提交了12次,单元测试终于全部通过,共增加了11行代码。
PR是提交了,是否被采纳就不知道了。也许代码写的比较挫,也许审核人员不认可我对Dapper的这种用法,是我用错了,没有修改的必要。
修改DynamicParameters.cs文件
变量定义:
private readonly HashSet<string> cleanNames = new HashSet<string>();
复制代码
单元测试始终无法全部通过,我添加了下面几行代码,终于成功了。原来cleanNames被重新new了之后,command.Parameters里可能是有值的,它的作用域更大一些。
foreach (IDbDataParameter param in command.Parameters)
{
if (!cleanNames.Contains(param.ParameterName))
{
cleanNames.Add(param.ParameterName);
}
}
复制代码
关键的修改就一行
原代码(参数很多时性能不行,参数什么情况下会很多呢?就是通过一条SQL批量Insert时会有很多参数,我是500条数据插入一批,参数根据表字段多少可能有几千个):
bool add = !command.Parameters.Contains(name);
复制代码
当command.Parameters中有几千个参数的时候,性能就惨不忍睹了。
集合查找的时间复杂度是O(N)。(原来我写的是O(N/2),现更正为O(N))
修改为(HashSet性能很高):
bool add = !cleanNames.Contains(name);
复制代码
通过HashSet查找,时间复杂度是O(1)。
往cleanNames中添加字段名:
if (add)
{
command.Parameters.Add(p);
cleanNames.Add(name);
}
复制代码
总结
关于List集合的Contains方法
当你使用Contains方法的时候,你要考虑这个集合有没有可能突然变的数据量很大?如果是在循环中频繁调用,并且List的数据量比较大,它的性能就比较差,建议使用HashSet或Dictionary来判查找。
但是HashSet、Dictionary和List转来转去也有代价,IDbCommand接口的Parameters属性的类型是IDataParameterCollection,它是一个集合,并没有HashSet或Dictionary类型的属性,又必须要转换才能得到。
提的issue和PR
issue:
https://github.com/DapperLib/Dapper/issues/1817
PR:
https://github.com/DapperLib/Dapper/pull/1816
LiteSql源码
LiteSql源于DBHelper,里面的接口是做过实际项目的,主要是ERP、CRM系统。
简单支持了Lambda表达式、增加了SqlString之后,使用上似乎变复杂了一点,不过原来的使用方式依然支持。
也许这里面的接口和设计思想,体现的是我上家公司的前辈们的技术水准。比如实体类用partial修饰分成两个文件,可能有利有弊吧。自动生成的Model类是不建议修改的,否则数据库变动的时候你还怎么自动生成?不把你的改动冲掉了?
一个ORM有它的设计思想和理念,比如DapperExtensions就不建议对实体类加特性,而是通过独立的映射类来处理表、字段别名,优缺点我还不清楚。
LiteSql的后续改进,还没有新的指导思想,所以一直都是小改,基本没怎么动。
https://gitee.com/s0611163/Dapper.LiteSql
https://gitee.com/s0611163/LiteSql
即使是大名鼎鼎的Dapper我依然不放心,所以保留了ADO.NET的版本。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复
使用道具
举报
0 个回复
倒序浏览
返回列表
快速回复
高级模式
B
Color
Image
Link
Quote
Code
Smilies
您需要登录后才可以回帖
登录
or
立即注册
本版积分规则
发表回复
回帖并转播
回帖后跳转到最后一页
发新帖
回复
嚴華
论坛元老
这个人很懒什么都没写!
楼主热帖
iOS全埋点解决方案-用户标识 ...
【万能皆可链接】C++中的动态链接库编 ...
用uniapp实现微信小程序的电子签名效果 ...
【云服务器】推荐阿贝云服务器,目前永 ...
【Selenium+Pytest+allure报告生成自动 ...
【Javaweb】Web工作原理、两种网页、两 ...
MySQL实战45讲 20
Spring Boot 配置文件
Qt-FFmpeg开发-打开本地摄像头(6) ...
微服务介绍
标签云
AI
运维
CIO
存储
服务器
浏览过的版块
运维.售后
快速回复
返回顶部
返回列表