sql 写query_为什么需要动态SQL

为什么需要动态SQL

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

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

介绍数据

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

d1919bb92151d3ecb3db25566ebc86c4.png

我在 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行。

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

593e37c7d27760dce395aac1de9c1f6c.png

如图,显示了一个极其简单的执行计划,确实进行了一次表扫描,读取了 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 AND

FoodMenuId = @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次),然后执行计划如下: 

f5447ed1e7215405c8c0b15484b72267.png

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

总结

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

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

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

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

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

7f465ee96e5b59ea1047a62948108bbf.png

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

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

相关文章

AMBA总线协议AHB、APB

一、什么是AMBA总线 AMBA总线规范是ARM公司提出的总线规范&#xff0c;被大多数SoC设计采用&#xff0c;它规定了AHB (Advanced High-performance Bus)、ASB (Advanced System Bus)、APB (Advanced Peripheral Bus)。AHB用于高性能、高时钟频率的系统结构&#xff0c;典型的应用…

安卓APP_ 控件(6)—— Notification通知

摘自&#xff1a;安卓APP_ 控件&#xff08;6&#xff09;—— Notification通知 作者&#xff1a;丶PURSUING 发布时间&#xff1a; 2021-04-02 00:30:14 网址&#xff1a;https://blog.csdn.net/weixin_44742824/article/details/115382674 Notification通知的使用 一、创建一…

安卓APP_ 控件(7)——Toolbar栏目样式

摘自&#xff1a;安卓APP_ 控件&#xff08;7&#xff09;——Toolbar栏目样式 作者&#xff1a;丶PURSUING 发布时间&#xff1a; 2021-04-02 15:42:07 网址&#xff1a;https://blog.csdn.net/weixin_44742824/article/details/115395997 Toolbar栏目样式 什么是Toolbar?设置…

Gartner:2013年SIEM市场分析(MQ)

2013年5月7日&#xff0c;Gartner一年一度的SIEM magic quadrant报告出炉了。如下图&#xff1a;对比一下去年的MQ矩阵&#xff1a;简言之&#xff0c;上榜厂商减少到16个&#xff0c;Q1Labs在三强竞争中稍占上风&#xff0c;Arcsight有所退步&#xff0c;Splunk终于跻身第一阵…

北林计算机考研真题答案,真题解析|『北林』2020年考研初试真题

原标题&#xff1a;真题解析&#xff5c;『北林』2020年考研初试真题真题解析&#xff5c;『北林』2020年考研初试真题前言从今年的考试题型来看未做改变&#xff0c;(选择、名词解释、简答、论述)但分数分布略有更改。从考试内容来看&#xff0c;基本持平于去年的难易程度&…

安卓APP_ 控件(8)—— AlertDialog

摘自&#xff1a;安卓APP_ 控件&#xff08;8&#xff09;—— AlertDialog 作者&#xff1a;丶PURSUING 发布时间&#xff1a; 2021-04-02 18:13:20 网址&#xff1a;https://blog.csdn.net/weixin_44742824/article/details/115400659 显示对话框&#xff0c;效果如下图&…

安卓APP_ 控件(9)—— PopupWindow弹窗

摘自&#xff1a;安卓APP_ 控件&#xff08;9&#xff09;—— PopupWindow弹窗 作者&#xff1a;丶PURSUING 发布时间&#xff1a; 2021-04-05 14:41:35 网址&#xff1a;https://blog.csdn.net/weixin_44742824/article/details/115405555 实现效果如下&#xff1a; 点击触发…

计算机网址登录教程,melogincn电脑登录教程

请问melogincn使用电脑登录设置的教程&#xff1f;在电脑上怎么登陆水星(美科星)无线路由器的后台&#xff0c;通过melogincn&#xff0c;试了下发现不知道如何打开&#xff0c;求分享用melogincn用电脑登录设置的教程。使用环境描述&#xff1a;melogincn实际上应该是melogin.…

从外网给新建的Exchange 2007/2010分发通讯组发邮件失败

前几天部署Exchange2010时建立了几个通讯组邮箱&#xff0c;测试下来发现只有exchange内部组员进行邮件交流没有问题&#xff0c;外网发送到组邮箱时会收到#550 5.7.1 RESOLVER.RST.AuthRequired; authentication required ##的错误&#xff0c;当时没有找出问题原因&#xff0…

安卓APP_ 布局(1)—— LinearLayout

摘自&#xff1a;安卓APP_ 布局&#xff08;1&#xff09;—— LinearLayout 作者&#xff1a;丶PURSUING 发布时间&#xff1a; 2021-04-05 16:46:22 网址&#xff1a;https://blog.csdn.net/weixin_44742824/article/details/115442240 LinearLatout 一、orientation&#xf…

鼠标点击测试_鼠标键盘如何检测故障,这边教您简单的测试

沉迷&#xff0c;教您简单的测试鼠标故障。有线键盘和鼠标的检测步骤&#xff1a;(1)将电脑关机&#xff0c;拔插对应的连接线。(2)移除所有除了键盘和鼠标之外的设备&#xff0c;然后重启电脑。(3)重启后&#xff0c;观察鼠标的灯是否有亮。点击滚动锁定键&#xff0c;观察键盘…

影响计算机的速度有哪些,影响电脑速度的硬件有哪些

影响电脑速度的硬件有哪些?影响最直接的是cpu、内存条、硬盘。其次是主板、显卡。一、处理器cpucpu是电脑的大脑&#xff0c;是运算核心和控制核心&#xff0c;它的主要作用是处理指令和数据&#xff0c;电脑所有的硬件工作分工都市cpu分配和协调的。所以&#xff0c;cpu的层次…

atom编写python程序_编写我们的第一个Python程序,print.py

Python安装后&#xff0c;默认会安装很多功能模块&#xff0c;方便开发应用程序时调用&#xff0c;需要增加默认功能模块以外的模块时&#xff0c;使用的是PIP 这个工具&#xff0c;把需要模块安装到C:\Users\Administrator\AppData\Local\Programs\Python\Python38-32\Lib\sit…

安卓APP_ 布局(2) —— RelativeLayout相对布局

摘自&#xff1a;安卓APP_ 布局&#xff08;2) —— RelativeLayout相对布局 作者&#xff1a;丶PURSUING 发布时间&#xff1a; 2021-04-05 20:19:54 网址&#xff1a;https://blog.csdn.net/weixin_44742824/article/details/115445242 RelativeLayout 一、根据父容器定位二、…

mutli-lane情况

PCIE3.0支持x1,x2,x4,x8,x16,x32 Lane widths. 在多条Lane情况下&#xff0c;有2类symbol framing&#xff0c;一类包含Ordered Sets&#xff0c;一类是TLP和DLLP。 Ordered Sets会同时在每条Lane上传输&#xff0c;所以每条Lane都会有完整的OS. 对于TLP/DLLP来说&#xff0c;S…

win10英雄联盟登录服务器未响应,win10系统英雄联盟登陆不上的解决方法

很多小伙伴都遇到过win10系统英雄联盟登陆不上的情况&#xff0c;想必大家都遇到过win10系统英雄联盟登陆不上的情况吧&#xff0c;那么应该怎么处理win10系统英雄联盟登陆不上呢&#xff1f;我们依照1、尝试打开网页或登录QQ查看是否正常能打开/登录&#xff0c;如果可以打开可…

玩转SSRS第六篇---客户端报表进阶

上一篇介绍了客户端报表的基本开发。此篇讲介绍如何给客户端报表自定义开发数据源。 通过上一篇我们知道可以通过Dataset的方式给报表添加数据源&#xff0c;这种方式通过UI操作的方式相对来说比较简单。此外我们也可以通过其它方式为客户端报表提供数据源&#xff0c;使数据的…

安卓APP_ 布局(3) —— FrameLayout帧布局

摘自&#xff1a;安卓APP_ 布局&#xff08;3) —— FrameLayout帧布局 作者&#xff1a;丶PURSUING 发布时间&#xff1a; 2021-04-05 20:41:02 网址&#xff1a;https://blog.csdn.net/weixin_44742824/article/details/115447658 帧布局的机制 从左上角开始绘制。 若有重叠&…

wpf page 界面渲染完成后执行自动操作_Vue项目骨架屏自动生成方案(dps)

什么是骨架屏什么是骨架屏呢&#xff1f;骨架屏(Skeleton Screen)是指在页面数据加载完成前&#xff0c;先给用户展示出页面的大致结构&#xff08;灰色占位图&#xff09;&#xff0c;在拿到接口数据后渲染出实际页面内容然后替换掉。Skeleton Screen 是近两年开始流行的加载控…

js等待当前线程内ajax完成,理解javascript定时器中的单线程

一、JavaScript 引擎是单线程的可以从下面的代码中看到&#xff0c;第一个用setTimeout中的代码是死循环&#xff0c;由于是单线程&#xff0c;下面的两个定时器就没机会执行了。setTimeout( function(){ while(true){} } , 100);setTimeout( function(){ alert(你好!setTimeou…