EF Core中的拆分查询策略

概要

从EF Core 5.0中,引入了拆分查询策略,该策略可以显著的提升多表查询的效率。本文主要介绍该策略的使用场景和基本使用方法。

代码和实现

使用场景

该策略主要使用在涉及多表连接查询的场景。本例的场景是这样,一个银行分行拥有多个设备,例如ATM机,麦当劳优惠劵ATM机或支票读取机。按照设备的不同,每种设备对应一个数据表。

如果查询分行包含的全部设备,需要多个数据表的联接,基本代码如下:

public async Task<List<Branch>> GetBranches() {List<Branch> branches = await _context.Set<Branch>().Where(b => b.IsDeleted == false).Include(b => b.Atms).Include(b => b.Cdms).Include(b => b.MCAtms).ToListAsync();return branches;}

我们先看一下,如果不加拆分策略,生成的单一SQL如下:

SELECT [t].[Id], [t].[Address], [t].[IsDeleted], [t].[Name], [t].[Rowversi
on], [t].[hasChequeService], [t].[hasCreditCardService], [t0].[Id], [t0].[Branch
Id], [t0].[DeviceStatus], [t0].[IsDeleted], [t0].[Name], [t0].[Rowversion], [t0]
.[SupportForeignCurrency], [t1].[Id], [t1].[BranchId], [t1].[CurrencyType], [t1]
.[DeviceStatus], [t1].[IsDeleted], [t1].[Name], [t1].[Rowversion], [t2].[Id], [t
2].[BranchId], [t2].[Campaign], [t2].[Coupon], [t2].[DeviceStatus], [t2].[IsDele
ted], [t2].[Name], [t2].[Rowversion], [t2].[SupportForeignCurrency]FROM [tt_branch] AS [t]LEFT JOIN [tt_atm] AS [t0] ON [t].[Id] = [t0].[BranchId]LEFT JOIN [tt_check_device] AS [t1] ON [t].[Id] = [t1].[BranchId]LEFT JOIN [tt_mcatm] AS [t2] ON [t].[Id] = [t2].[BranchId]WHERE [t].[IsDeleted] = CAST(0 AS bit)ORDER BY [t].[Id], [t0].[Id], [t1].[Id]

我们可以看到,EF Core是使用的左联方式加载相关的设备数据表。

现在我们尝试增加拆分策略,代码如下:

public async Task<List<Branch>> GetBranches() {List<Branch> branches = await _context.Set<Branch>().Where(b => b.IsDeleted == false).AsSplitQuery().Include(b => b.Atms).Include(b => b.Cdms).Include(b => b.MCAtms).ToListAsync();return branches;
}
info: Microsoft.EntityFrameworkCore.Database.Command[20101]Executed DbCommand (119ms) [Parameters=[], CommandType='Text', CommandTime
out='30']SELECT [t].[Id], [t].[Address], [t].[IsDeleted], [t].[Name], [t].[Rowversi
on], [t].[hasChequeService], [t].[hasCreditCardService]FROM [tt_branch] AS [t]WHERE [t].[IsDeleted] = CAST(0 AS bit)ORDER BY [t].[Id]
info: Microsoft.EntityFrameworkCore.Database.Command[20101]Executed DbCommand (9ms) [Parameters=[], CommandType='Text', CommandTimeou
t='30']SELECT [t0].[Id], [t0].[BranchId], [t0].[DeviceStatus], [t0].[IsDeleted],
[t0].[Name], [t0].[Rowversion], [t0].[SupportForeignCurrency], [t].[Id]FROM [tt_branch] AS [t]INNER JOIN [tt_atm] AS [t0] ON [t].[Id] = [t0].[BranchId]WHERE [t].[IsDeleted] = CAST(0 AS bit)ORDER BY [t].[Id]
info: Microsoft.EntityFrameworkCore.Database.Command[20101]Executed DbCommand (3ms) [Parameters=[], CommandType='Text', CommandTimeou
t='30']SELECT [t0].[Id], [t0].[BranchId], [t0].[CurrencyType], [t0].[DeviceStatus
], [t0].[IsDeleted], [t0].[Name], [t0].[Rowversion], [t].[Id]FROM [tt_branch] AS [t]INNER JOIN [tt_check_device] AS [t0] ON [t].[Id] = [t0].[BranchId]WHERE [t].[IsDeleted] = CAST(0 AS bit)ORDER BY [t].[Id]
info: Microsoft.EntityFrameworkCore.Database.Command[20101]Executed DbCommand (5ms) [Parameters=[], CommandType='Text', CommandTimeou
t='30']SELECT [t0].[Id], [t0].[BranchId], [t0].[Campaign], [t0].[Coupon], [t0].[D
eviceStatus], [t0].[IsDeleted], [t0].[Name], [t0].[Rowversion], [t0].[SupportFor
eignCurrency], [t].[Id]FROM [tt_branch] AS [t]INNER JOIN [tt_mcatm] AS [t0] ON [t].[Id] = [t0].[BranchId]WHERE [t].[IsDeleted] = CAST(0 AS bit)ORDER BY [t].[Id]

我们可以看到,生成的查询语句进行了拆分,在查询到现有的分行数据后, 分别对不同的设备表,进行了内联查询。

拆分查询的好处就是每次以内联的方式,只联接一张表,避免同时左联多个可能很大的表,从而引发的性能问题。

另一个好处如下:

public async Task<List<Branch>> GetBranches() {List<Branch> branches = await _context.Set<Branch>().Where(b => b.IsDeleted == true).AsSplitQuery().Include(b => b.Atms).Include(b => b.Cdms).Include(b => b.MCAtms).ToListAsync();return branches;}

如果在第一个表中,没有查询到数据,后面的联表操作也就不会进行,这样如果后面有很大的字典表,根本就不会再去查询,从而提高的查询的性能。

该查询生成的SQL如下:

     info: Microsoft.EntityFrameworkCore.Database.Command[20101]Executed DbCommand (256ms) [Parameters=[], CommandType='Text', CommandTime
out='30']SELECT [t].[Id], [t].[Address], [t].[IsDeleted], [t].[Name], [t].[Rowversi
on], [t].[hasChequeService], [t].[hasCreditCardService]FROM [tt_branch] AS [t]WHERE [t].[IsDeleted] = CAST(1 AS bit)ORDER BY [t].[Id]

上面的代码中,只有分行的查询,因为分行查询结果为空,所以就直接返回,不需要再进行后面的查询。

拆分查询的副作用

由于拆分策略将原有的单次查询,分割成多次数据库交互查询,每次的查询结果将被放到缓存中,这样如果查询过的数据表,在结果汇总返回之前,又被修改,可能会导致数据一致性的问题。

在分页和排序方面,如果涉及分页,必须保证排序方式的唯一性,如果排序的内容相同,则无法保证每次的查询结果都是一样的,即使数据没有被修改过,也无法保证。所以如果涉及分页,请慎用该策略。

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

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

相关文章

【通义千问】大模型Qwen GitHub开源工程学习笔记(4)-- 模型的量化与离线部署

摘要: 量化方案基于AutoGPTQ,提供了Int4量化模型,其中包括Qwen-7B-Chat和Qwen-14B-Chat。更新承诺在模型评估效果几乎没有损失的情况下,降低存储要求并提高推理速度。量化是指将模型权重和激活的精度降低以节省存储空间并提高推理速度的过程。AutoGPTQ是一种专有量化工具。…

[每周一更]-(第67期):docker-compose 部署php的laravel项目

容器化部署laravel框架的php项目 操作步骤 参考&#xff1a; https://www.cnblogs.com/jingjingxyk/p/16842937.htmlhttps://developer.aliyun.com/article/708976 0、plv项目修改 composer install.env 修改后台地址 IP:端口chmod -R 777 public / chmod -R 777 storagevi…

Mac删除不在程序坞的程序

现象描述&#xff1a;删除某个程序时&#xff08;通过‘程序’列表中将该应用移动到废纸篓里&#xff09;&#xff0c;该应用程序正在运行中&#xff0c;删除过程该程序未提示正在运行中&#xff0c;仅仅删除了图标&#xff08;在此吐槽下该程序的交互&#xff0c;产品没有考虑…

*常用函数

文章目录 nn.PReLU() 激活函数 nn.PReLU() 激活函数 PReLU(Parametric Rectified Linear Unit), 顾名思义&#xff1a;带参数的ReLU 其中a代表的是可学习的参数 ReLU、PReLU的比较&#xff1a; 如果ai0&#xff0c;那么PReLU退化为ReLU&#xff1b; 如果ai是一个很小的固定…

Git Commit Message规范

概述 Git commit message规范是一种良好的实践&#xff0c;可以帮助开发团队更好地理解和维护代码库的历史记录。它可以提高代码质量、可读性和可维护性。下面是一种常见的Git commit message规范&#xff0c;通常被称为"Conventional Commits"规范&#xff1a; 一…

Windows下DataGrip连接Hive

DataGrip连接Hive 1. 启动Hadoop2. 启动hiveserver2服务3. 启动元数据服务4. 启动DG 1. 启动Hadoop 在控制台中输入start-all.cmd后&#xff0c;弹出下图4个终端&#xff08;注意终端的名字&#xff09;2. 启动hiveserver2服务 单独开一个窗口启动hiveserver2服务&#xff0c;…

Kafka基础入门

Kafka介绍 Kafka是什么&#xff1f; kafka是一种分布式的&#xff0c;基于发布/订阅的消息系统。 Kafka的特点 分布式&#xff0c;吞吐量高&#xff0c;发布订阅模式&#xff0c;轻量灵活&#xff0c;较长时间持久化 Kafka的应用场景 解耦 原先一个微服务是通过接口&…

0基础学习VR全景平台篇 第108篇:全景图细节处理(下,航拍)

上课&#xff01;全体起立~ 大家好&#xff0c;欢迎观看蛙色官方系列全景摄影课程&#xff01; &#xff08;调色前图库&#xff09; &#xff08;原图-大图&#xff09; 一、导入文件 单击右下角导入按钮&#xff0c;选择航拍图片所在文件夹&#xff0c;选择图片&#xff0…

【运维笔记】swow源码编译安装

swow的github网址 https://github.com/swow/swow 从github中拉取源码 git pull https://github.com/swow/swow.git 编译安装 github中readme文件讲述了安装方法 这里整理了命令&#xff0c;进入拉取项目的目录后依次执行命令即可 #pwd 确保自己在swow目录中&#xff0c;如…

docker 搭建本地Chat GPT

要在CentOS7上安装Docker&#xff0c;您可以按照以下步骤进行操作&#xff1a; 1、更新系统包列表 sudo yum update2、安装Docker存储库的必要软件包 sudo yum install -y yum-utils device-mapper-persistent-data lvm23、添加Docker存储库 sudo yum-config-manager --add…

3DEXPERIENCE® SOLIDWORKS® 新功能

先前版本的兼容性 优点 即使其他用户正在使用旧版 SOLIDWORKS&#xff0c;也能轻松与其 协作。 • 通过将您的 3DEXPERIENCE SOLIDWORKS 设计作品保存为旧 版本&#xff0c;与使用旧版本的供应商无缝协作。 • 将零件、装配体和工程图保存为最新版本前两年之内的 3DEXPERIENC…

centos7部署Nginx和RabbitMQ

文章目录 Nginx安装部署【简单】简介安装 RabbitMQ安装部署【简单】简介安装 Nginx安装部署【简单】 简介 Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器&#xff0c;同时也提供了IMAP/POP3/SMTP服务。Nginx可以托管用户编写的WEB应用程序成为可访问的网页服务&am…

从零开始使用webpack搭建一个react项目

先做一个正常编译es6语法的webpack demo 1. 初始化package.json文件 npm init一路enter下去 2. 添加插件 {"name": "demo","version": "1.0.0","description": "","main": "index.js",&q…

Maven 密码加密

一、简介 Maven支持服务器密码加密。该解决方案解决的主要用例是&#xff1a; 多个用户共享同一台生成计算机&#xff08;服务器、CI 框&#xff09;有些用户有权将 Maven 工件部署到存储库&#xff0c;有些则没有。 这适用于任何需要授权的服务器操作&#xff0c;而不仅仅是…

《RISC-V体系结构编程与实践》的benos_payload程序——mysbi跳转到benos分析

1、benos_payload.bin结构分析 韦东山老师提供的开发文档里已经对程序的结构做了分析&#xff0c;这里不再赘述&#xff0c;下面是讨论mysbi跳转到benos的问题&#xff1b; 2、mysbi跳转到benos的代码 3、跳转产生的疑问 我认为mysbi.bin最后跳转到0x22000地址处执行&#xff0…

boost Geometry

boost::Geometry boost作为C中最常用的第三方库&#xff0c;Geometry库里面拥有大量的开源算法。 函数作用get获取几何图形&#xff08;通常为点&#xff09;的坐标值get (with index)获取框或段的坐标值set设置几何图形&#xff08;通常为点&#xff09;的坐标值set (with i…

C/S架构学习之多进程实现TCP并发服务器

多进程实现TCP并发服务器的实现流程&#xff1a;一、自定义信号处理函数&#xff08;sig_func函数&#xff09;&#xff1a; void sig_func(int signum){wait(NULL);}wait函数: #include <sys/types.h>#include <sys/wait.h>pid_t wait(int *wstatus);/*功能&#…

Pytorch从零开始实战05

Pytorch从零开始实战——运动鞋识别 本系列来源于365天深度学习训练营 原作者K同学 文章目录 Pytorch从零开始实战——运动鞋识别环境准备数据集模型选择数据可视化模型预测总结 环境准备 本文基于Jupyter notebook&#xff0c;使用Python3.8&#xff0c;Pytorch2.0.1cu118…

python udp 线程接受 demo

udp使用socketserver 接受简单方便 使用是python 的threading 快速构建udp 接受线程 使用 pyqt5的QThread&#xff0c;用于发现信号到ui线程&#xff0c;跟新ui 使用queue接受udp数据&#xff0c;并通过queue在 udp接受线程和数据解析线程间数据传递。 from socketserver impo…

代码混淆界面介绍

代码混淆界面介绍 代码混淆功能包括oc&#xff0c;swift&#xff0c;类和函数设置区域。其他flutter&#xff0c;混合开发的最终都会转未oc活着swift的的二进制&#xff0c;所以没有其他语言的设置。 代码混淆功能分顶部的显示控制区域&#xff1a;显示方式&#xff0c;风险等…