C#大型电商项目优化(二)——嫌弃EF与抛弃EF
上一篇博文中讲述了使用EF开发电商项目的代码基础篇,提到EF后,一语激起千层浪。不少园友纷纷表示:EF不适合增长速度飞快的互联网项目,EF只适合企业级应用等等。
也有部分高手提到了分布式,确实,性能优化从数据库出发,初期就加索引,然后垂直拆分,水平拆分,读写分离,甚至是分布式事务,阳春白雪,格局很高。然而笔者希望通过渐进的过程来优化这个项目,我们缩小格局,从细节查看不同方案的优劣。
之前提过,使用EF最主要的原因是项目时间紧迫,EF搭建速度快,熟悉的同事也多,使用方便。这个决策确实帮助我们挺过了初期的难关。在业务量增长的过程中,一些问题也逐渐暴露出来,我们开始针对问题做优化。
问题1:部分请求响应缓慢,影响用户体验。
使用EF做数据的增删改查,一些不规范代码也会拖慢程序效率,笔者在上一篇中已经提过。某些请求中可能包含多次数据查询与更新,如果这些细小的问题都以低效运行,那这个请求确实会很慢。然而在EF的框架下优化它,也未必能收到明显成效。以更新商品销量为例,我们上方案与代码:
方案1
先查出某一条数据,然后填入新算出的销量,再更新数据库,代码如下:
//先查出数据,再更新
var productSKU = unitOfWork.ProductSku.GetByID(dtos[].Items[].SKUId);
productSKU.SalesCount = productSKU.SalesCount + dtos[].Items[].Quantity;
unitOfWork.ProductSku.Update(productSKU);
unitOfWork.Submit();
其响应时间如图:
方案2
采用IQuryable,之前提到过,这种查询方式不会真的将全部数据加载到内存,代码如下:
//2采用IQueryable查询更新
var productSKU1 = unitOfWork.ProductSku.Get(p => p.Id == dtos[].Items[].SKUId);
foreach (var item in productSKU1)
{
item.SalesCount = item.SalesCount + dtos[].Items[].Quantity;
unitOfWork.ProductSku.Update(item);
}
unitOfWork.Submit();
其响应时间如图:
方案3
直接使用SQL,简单粗暴,代码如下:
//3直接使用sql更新
string updateSql = @"update ProductSKU set SalesCount=SalesCount+" + dtos[].Items[].Quantity + " where Id='" + dtos[].Items[].SKUId.ToString() + "'";
unitOfWork.ProductSku.ExecuteSqlCommand(updateSql);
unitOfWork.Submit();
其响应时间如图:
我们来分析下这三种方案:
方案1简单易懂,将数据查出来,更新后再塞回数据库,逻辑清晰,代码更清晰。可是将数据取出来,加载到内存,再对内存里的数据进行修改,最后生成SQL送回数据库执行,这套走下来,好像兜了一大圈,其实我们只想更新个销量。
方案2显得好了些,使用了我们在前一篇中讲到的理念,不将数据整个加载到内存,只到用时才加载,通过这种方式更新,其实生成的SQL和直接执行SQL差不太多了,但是我们可以发现:方案2和方案1时间差不多。在笔者预期中,方案2应该是比方案1好的,至于时间差不多的原因,应该是方案2用了一次循环,第二次循环时不符合条件,然后跳出循环,造成了些许时间浪费。如果是批量更新销量,方案2必然比方案1优秀很多。
方案3自然是简单粗暴,一条SQL搞定,毫不拖泥带水,其效果也是喜人的,几乎比方案1快1倍!
之前有园友提到索引的问题,其实我厂有专职DBA,不仅为数据量较大的表添加了聚集索引和非聚集索引,还写了定时任务去更新索引。所以索引这块我们不深究。
早起追逐开发效率阶段,我们可能将方案1优化为方案2,然后继续做新功能开发。但是现在我们有更多的选择,我们也有更多的时间去深究用户体验与系统效率了,那么自然的,我们开始嫌弃EF了。但是开发到这个程度,再去更换框架似乎不合适。而且大道至简,如果能用SQL搞定,那必是极好的。于是乎,我们开始对关键部分业务代码做重构,替换为原生SQL。这似乎是抛弃EF的开端。
问题2:部分数据量很大的表需要分表,EF难以维系
EF是ORM框架,映射数据库对象,然而同一数据库的一张表被拆分为两张以上,EF似乎没法映射了,两张表字段完全一致,难道再写个Model?而且分表是个动态的过程,也许一年分一次,也许一个月分一次,而且可能是定时任务去执行的,总不能一分表就改代码。自此,我们和EF的矛盾激化了。
园子里有关于数据库拆分的博客,我们所要改的只有数据访问层,最好不要动业务层。而且我们上文也提到:用原生SQL。那么我们就用原生SQL重写数据访问。
这里举个例子,比如我们拆分订单表,按年拆分,通常用户只会查看当年的订单,所以主表的查询次数肯定比其他分出的表要多,如果有用户要查往年的订单,我们再将查询范围扩大。按照这样的理念,我们开始重写数据访问层,并按照以下要点执行:
1.使用原生SQL
2.添加日期参数,如果日期超出主表的范围,则开始连接查询
3.查询中也可以添加其他条件,将参数作为对象填入SQL
4.抽象出一个生成SQL的公共方法,方便大家调用
拼装SQL是一件极其考验基本功的事,这个公共方法是我厂一位大师级的数据专家抽象出来的,大家也可以按照这个思路尝试下,一个简化版是很容易做出来的。
至此,项目中重要的业务功能已经和EF脱离关系了,我们也欣喜地收获了SQL带来的效率。而其他功能模块中,没有高并发场景或并不常用的应用,我们并没有做重构。
尽管本文标题是嫌弃,但如果是企业级应用,需要兼顾开发效率,且没有互联网模式下的业务量激增状况,笔者仍然推荐使用EF。
C#大型电商项目优化(二)——嫌弃EF与抛弃EF的更多相关文章
- C#大型电商项目优化(三)——扩展性与支付
上一篇文章引来不少非议,笔者并非对EF有看法,而是针对不同的业务场景和框架背景,挑选不同的方案.每个方案都有其优势劣势,挑选最快速,最简单的方案,是笔者的初衷. 看评论也是学习的过程,然而有些只做评价 ...
- C# 大型电商项目性能优化(一)
经过几个月的忙碌,我厂最近的电商平台项目终于上线,期间遇到的问题以及解决方案,也可以拿来和大家多做交流了. 我厂的项目大多采用C#.net,使用逐渐发展并流行起来的EF(Entity Framewor ...
- Spark大型电商项目实战-及其改良之番外(1)-将spark前端页面效果高效拷贝至博客
Spark大型电商项目实战-及其改良这个系列的时间轴展示图一直在变....1-3篇是用图直接表示时间轴,用一段简陋的html代码表示时间表.第4篇开始才是用比较完整的前端效果,能移动.缩放时间轴,鼠标 ...
- vue大型电商项目尚品汇(前台篇)day01
学完vue2还是决定先做一个比较经典,也比较大的项目来练练手好一点,vue3的知识不用那么着急,先把vue2用熟练了,vue3随时都能学. 这个项目确实很经典包含了登录注册.购物车电商网站该有的都有, ...
- Spark大型电商项目实战-及其改良(2) RDD优化效果不稳定的真正原因
首先看没有map join的第2任务: 时间线如下 接着是对应id的算子计算时间表 Stage Id Description Submitted Duration Tasks: Succeeded/T ...
- Spark大型电商项目实战-及其改良(1) 比对sparkSQL和纯RDD实现的结果
代码存在码云:https://coding.net/u/funcfans/p/sparkProject/git 代码主要学习https://blog.csdn.net/u012318074/artic ...
- vue大型电商项目尚品汇(前台篇)day02
现在正式回归,开始好好做项目了,正好这一个项目也开始慢慢的开始起色了,前面的准备工作都做的差不多了. 而且我现在也开始慢慢了解到了一些项目才开始需要的一些什么东西了,vuex.router这些都是必备 ...
- vue大型电商项目尚品汇(前台篇)day04
这几天一直都在做项目,只是没有上传上来,即将把前台项目完结了.现在开始更新整个前台的部分 一.面包屑处理 1.分类操作 点击三级联动进入搜索产生面包屑,直接取参数中的name即可 点击x怎么干掉这个面 ...
- vue大型电商项目尚品汇(前台篇)day05
紧急更新第二弹,然后就剩下最后一弹,也就是整个前台的项目 一.购物车 1.加入购物车(新知识点) 加入到购物车是需要接口操作的,因为我们需要将用户的加入到购物车的保存到服务器数据库,你的账号后面才会在 ...
随机推荐
- linux 开机自启动脚本
在/etc/rc.local文件中添加自启动命令(其中一种方法) 1.案例,就用博主本人之前发的博文 “nginx + flask + uwsgi + centos + python3 搭建web项目 ...
- 纯CSS选项卡
html: <!doctype html> <html> <head> <meta charset="utf-8"> <tit ...
- Red5视频流服务器安装
一.安装jre JAVA运行时下载地址: https://www.java.com/zh_CN/download/manual.jsp 安装后设置环境变量,变量值是jre的安装路径 二.安装 red5 ...
- iTween for Unity
你曾经在你的游戏中制作过动画吗?问这个问题可能是愚蠢的,几乎每个Game都有动画,虽然有一些没有,但你必须处理有动画和没有动画.让我们结识 ITween. iTween 官方网站:http://itw ...
- Windows 10更新后频繁死机、假死(SSD)
问题详情: 新版的Windows改变了更新策略,无法设置为不更新系统.在系统更新后,之前的部分设定也会神奇丢失,包括之前设定的解决的这个卡顿问题.于是重新爬文章找解决方案,在这里做个备份. 本文章内容 ...
- Linux 小知识翻译 - 「小型移动式PC」
这次介绍下新闻上提到的「小型移动式PC」.(这个当时日本新闻上的内容) 最近,经常在日本的大卖场中看到一种小型的移动式PC.不仅是小巧方便携带,而且价格也便宜.而且,省电功能的加入,使电池能工作更长的 ...
- Linux 小知识翻译 - 「模块」
说起module(模块),有的像「可热插拔的零部件」的意思. 在讨论Linux时提到的模块一般是指可以组装到内核中的模块. 模块这个概念是在硬件和程序设计领域中广泛使用的概念.我们这次说的模块特指Li ...
- deepin安装Oracle jdk8,以及添加add-apt-repository命令支持
@font-face{ font-family:"Times New Roman"; } @font-face{ font-family:"宋体"; } p.M ...
- 17秋 软件工程 团队第五次作业 Alpha Scrum9
17秋 软件工程 团队第五次作业 Alpha Scrum9 今日完成的任务 世强:APP后端部门申请状态: 港晨:主页面代码实现: 树民:完善超级管理员web后端: 伟航:设置页面和侧边栏的原型: 陈 ...
- 如何根据name和value选中radio [问题点数:40分,结帖人zzxap
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <he ...