为什么需要动态SQL

为什么需要动态SQL

在使用 EF或者写 SQL语句时,查询条件往往是这样一种非常常见的逻辑:如果客户填了查询信息,则查询该条件;如果客户没填,则返回所有数据。

我常常看到很多人解决这类问题时使用了错误的静态 SQL的解决办法,使得数据库无法利用索引,导致性能急剧下降。

介绍数据

这次我将使用我的某客户的真实数据来演示(已确认不涉及信息安全????),有一个订单表 FoodOrder,结构如下: 

我在 Id、 FoodMenuId、 OrderUserId上创建了非聚集索引,在 OrderTime上创建了聚集索引。该表有 51652条数据。

静态SQL

在这种逻辑中如果想用一条 SQL语句搞定所有查询,那么代码可能长这个样子:

set statistics io on
declare @userId int = 506
declare @menuId int = 3176
select * from FoodOrder where (@userId is null or OrderUserId = @userId) AND(@menuId is null or FoodMenuId = @menuId)

这种写法虽然方便,但基于其 SQL过于“复杂”,甚至还使用了 IS NULL和 OR,导致语句完全无法使用索尼,运行 SET STATISTICS IO ON后,显示信息如下:

(3 行受影响)
Table 'FoodOrder'. Scan count 1, logical reads 337, physical reads 0, page server reads 0, read-ahead reads 0, page server read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.

显示其进行了一次表扫描,并进行了 337次逻辑读,输出数据只有 3行。

然后看看实际的执行计划: 

如图,显示了一个极其简单的执行计划,确实进行了一次表扫描,读取了 51652行数据,并且完全没有走索引。

动态SQL

而动态 SQL,就是将查询条件中的判断语句,提前在代码中判断完成,而放到数据库(如 SQLServer)中执行时就是简单的、可利用索引的 SQL语句了,在这个例子中,判断 @userId和 @menuId是否为 null的代码,可能会长这个样子(如果是 Dapper):

var sql = new StringBuilder();
sql.Append("SELECT * FROM FoodOrder WHERE 1=1 ");
if (userId != null) 
{sql.AppendLine("AND OrderUserId = @userId");
}
if (menuId != null)
{sql.AppendLine("AND FoodMenuId = @menuId");
}
// ...

如果是 EF,代码可能是这个样子:

IQueryable<FoodOrder> query = db.FoodOrders;
if (userId != null)
{query = query.Where(x => x.OrderUserId == userId);
}
if (menuId != null)
{query = query.Where(x => x.FoodMenuId = menuId);
}
// ...

这样一来,最终在数据中执行的 SQL语句就比较简单了,如果客户确实传了 userId和 menuId两个参数, SQL就应该长这个样子:

select * from FoodOrder where OrderUserId = @userId ANDFoodMenuId = @menuId

运行的 setstatistics io on结果如下:

(3 行受影响)
Table 'FoodOrder'. Scan count 2, logical reads 11, physical reads 0, page server reads 0, read-ahead reads 0, page server read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.

显然仅进行了 11次逻辑读(相比静态 SQL的 337次),然后执行计划如下: 

显示进行了两次 IndexSeek,显然是走了索引,显示查询开销只占 5%,而之前的开销占 95%,性能区别高达 20倍以上。

总结

据说上次博客园出现性能问题,就是因为 EFCore3.0有这个 bug,会生成多余的 IS NOT NULL(链接:EF Core 3.0 Preview 9 的2个小坑),这个 bug已经确认最新的 EFCore3.1中解决。

就像文中所说的动态 SQL,我认为理解数据库、对写出高性能的应用程序至关重要——这显而易见,但其实又很容易忽略。忽略的原因不仅是因为新手,很多老手有时因为“互联网”思维和“设计模式”等原因,也会有意忽略数据库的理解。

现在很多“互联网”应用思维认为,数据库就是一个仓库,它应该只负责其最“擅长”的增删改查功能即可,其它的应该都交由缓存来解决。有句话说得好,就是命名和缓存失效,是编程界最困难的两个问题。缓存有缓存的问题,不好好理解数据库,就必须花大量时间好好理解缓存。设计一个正确的缓存往往又比花大量时间设计数据库要复杂得多。

另外现在流行的“领域驱动设计”( DDD)也主张应用应该先从业务逻辑开始抽象,数据库和性能往往成为他们首先忽略的对象,最后可能也得加个“缓存”来解决,导致原来简单的系统急剧膨胀,复杂不堪。这种过度设计、人云亦云的做法值得深思。

喜欢的朋友 请关注我的微信公众号:【DotNet骚操作】

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/312576.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【好文】为什么必须学好.Net Core?怎样弯道超车新年高薪?这样做,一周就够了!(文末彩蛋)...

都2020了你还不会.Net Core&#xff1f;恕我直言&#xff0c;2020年还不会.Net Core是会被淘汰的&#xff01;12月3号&#xff0c;.Net Core3.1的LTS版正式发布&#xff0c;4年来7个正式版本和几十个Preview版本&#xff0c;热烈可见一斑&#xff01;越来越多的互联网软件公司开…

基于 Kubernetes 的基础设施即代码

11 月 9、10 号两天&#xff0c;.NET 社区第一次以“.NET 大会”为品牌在上海召开了第一届峰会&#xff0c;现场与会者达到 600 人规模。大会的第 1 天是各类演讲分享&#xff0c;第 2 天有多个动手实践课。张善友队长、 刘腾飞 和我一起策划了基于 Kubernetes 的 .NET Core 微…

Steeltoe 2.4新增代码生成工具、全新入门指南等,助力.NET微服务开发

Steeltoe框架现可帮助.NET开发人员创建云原生应用。随着其功能的扩充&#xff0c;该框架越来越受欢迎&#xff0c;下载量达到580万&#xff08;并且仍在增加&#xff09;&#xff0c;这其中大部分的功能创新都源自于用户反馈、社区贡献和.NET运行环境各方面的改进。但这些还不够…

2019 年终回顾:不忘初心,负重前行

点击上方蓝字关注“汪宇杰博客”导语2019 年就要接近尾声&#xff0c;这一年对于我来说&#xff0c;有许多有意义的事件。我成长了许多&#xff0c;并依然保持着对技术的热情。在辞旧迎新之际&#xff0c;我想回顾一下我这一年中有意义的事件与收获&#xff0c;期待与大家一起在…

【C#】设计模式的学习征途系列文章目录(2019版)

Photo &#xff1a;Design Patterns文 | Edison Zhou2017年&#xff0c;我开始系统学习设计模式&#xff0c;参考了《大话设计模式》、《设计模式的艺术》等书籍&#xff0c;并通过C#语言写了各种模式的代码示例&#xff08;已经放到了我的github上并收获了120个star&#xff0…

原创 | 为什么年终奖是一个彻头彻尾的职场圈套?

0前言之前写过几篇职场专题的文章&#xff0c;反响不错&#xff0c;也先后被不少公众号转载过&#xff0c;这几天来了不少新朋友&#xff0c;如果之前没阅读过&#xff0c;可以在后台回复“职场”2个字&#xff0c;查看系列文章。转眼又到年底了&#xff0c;不知道有多少人在心…

Blazor 机制初探以及什么是前后端分离,还不赶紧上车?

上一篇文章发了一个 BlazAdmin 的尝鲜版基于 Blazui 的 Blazor 后台管理模板 BlazAdmin 正式尝鲜&#xff0c;这一次主要聊聊 Blazor 是如何做到用 C# 来写前端的&#xff0c;传送门&#xff1a;https://www.cnblogs.com/wzxinchen/p/12057171.html飚车前需要说明的一点是&…

云原生

一、云原生概念的诞生云原生&#xff08;Cloud Native&#xff09;的概念&#xff0c;由来自Pivotal的MattStine于2013年首次提出&#xff0c;被一直延续使用至今。这个概念是Matt Stine根据其多年的架构和咨询经验总结出来的一个思想集合&#xff0c;并得到了社区的不断完善&a…

基于 Kubernetes 的 CICD 基础设施即代码

在上一篇基于 Kubernetes 的基础设施即代码一文中&#xff0c;我概要地介绍了基于 Kubernetes 的 .NET Core 微服务和 CI/CD 动手实践工作坊 使用的基础设施是如何使用代码描述的&#xff0c;以及它的自动化执行过程。如果要查看基于 Kubernetes 的基础设施即代码架构全图&…

Azure Arc:微软是怎么玩多云游戏的?

混合云在竞争性云提供商的基础上提供了来自云提供商的服务&#xff0c;从而使组织能够以不同方式一起使用来自不同供应商的云服务。例如&#xff0c;组织可以使用将数据存储在一个云中存储上的功能&#xff0c;而另一个云服务商则在该应用程序或数据之上运行。因此&#xff0c;…

当我们在谈 .NET Core 跨平台时,我们在谈些什么?--学习笔记

摘要.NET Framework在过去十多年在跨平台上的尝试。.NET Core跨平台的实现有何不同&#xff1f;基于 .NET Standard的平台兼容性是如何实现的&#xff1f;讲师介绍历史枷锁.NET Framework FCL CLR"跨平台"的 .NET Framework完全独立&#xff0c;各自为政复用之殇由…

IdentityServer4学习笔记汇总(实现传送门在底部)

前言互联网时代,对信息和资源的保护越发苛刻,在所有应用中授权和认证是必不可少缺少的一部分。如果一个应用没有授权和认证那么这个应用就是不完整或者说不安全的应用。在.Net平台给我们提供了一套完整的授权认证框架,那就是IdentityServer4。它实现了OpenId Connect和OAuth2.0…

多库操作2:终于实现多个数据库操作

▼更多精彩推荐&#xff0c;上午10点到达▼圣诞节快乐在上周的文章【多库操作&#xff1a;多个数据库的动态切换&#xff08;一&#xff09;】中&#xff0c;我们简单说了说&#xff0c;如何切换数据库&#xff0c;虽然实现了大部分的功能&#xff0c;但是最后也遗留了小问题&a…

服务发现技术是如何演进出来的?

昨天写了一篇<微服务的时间和成本去哪儿了>&#xff0c;有人在底下留言&#xff1a;我的回答是&#xff1a;"微服务可以不用服务发现和负载均衡吗&#xff1f;它是微服务一个核心组件。怎么能说没有关系&#xff1f;"我觉得有必要来思考和总结一下服务发现技术…

3分钟搞懂前后端开发的区别

上周末见了好多开发的年轻朋友&#xff0c;问了我一个问题&#xff1a;“前后端的区别和要求是什么&#xff1f;”分不清前后端开发的区别和要求&#xff0c;一种是因为前后端都了解&#xff0c;号称“全栈工程师”&#xff0c;但又什么都不是很精通&#xff1b;另一种是前端的…

基于 Kubernetes 的微服务部署即代码

在基于 Kubernetes 的基础设施即代码一文中&#xff0c;我概要地介绍了基于 Kubernetes 的 .NET Core 微服务和 CI/CD 动手实践工作坊使用的基础设施是如何使用代码描述的&#xff0c;以及它的自动化执行过程。如果要查看基于 Kubernetes 的基础设施即代码架构全图&#xff0c;…

使用Arduino开发ESP32开发环境搭建

1.打开Arduino IDE&#xff0c;选择文件->首选项->设置 复制下方的ESP32板管理网址&#xff0c;添加到附加开发板管理器中&#xff1a; https://dl.espressif.com/dl/package_esp32_index.json 2.选择&#xff1a;工具->开发板->开发板管理器 在弹出的对话框中搜索…

.NET ORM FreeSql 第一个正式版本发布 v1.0.0

一、简介FreeSql 是 .NET 平台下的对象关系映射技术(O/RM)&#xff0c;支持 .NetCore 2.1 或 .NetFramework 4.0 或 Xamarin。从 0.0.1 发布到今历时整整一年的迭代更新&#xff0c;现在终于敢发布第一个正式版。本文内容从简&#xff0c;介绍项目的主要功能框架&#xff0c;以…

Windows上搭建EMQTT服务器

1.官网下载EMQ 2.复制如图文件路径 3.打开终端cmd&#xff0c;输入&#xff1a; 再输入&#xff1a; 4.打开浏览器&#xff0c;进入&#xff1a;http://192.168.1.25:18083/* (localhost可打开终端输入ipconfig查看) 用户名&#xff1a;admin 密码&#xff1a;public

.NET解所有相机RAW格式照片

再聊.NET解相机RAW格式照片上次我发了一篇文章《用.NET解索尼相机ARW格式照片》&#xff0c;提到通过安装 SonyRawFileDecoder的方式&#xff0c;然后调用 WindowsImagingComponents来解析 RAW格式文件。后来我经过进一步研究、探索&#xff0c;发现还有更简单的办法。新的方法…