[NewLife.XCode]高级查询(化繁为简、分页提升性能)

NewLife.XCode是一个有10多年历史的开源数据中间件,支持nfx/netcore,由新生命团队(2002~2019)开发完成并维护至今,以下简称XCode。

整个系列教程会大量结合示例代码和运行日志来进行深入分析,蕴含多年开发经验于其中,代表作有百亿级大数据实时计算项目。

开源地址:https://github.com/NewLifeX/X (求star, 754+)

 

回到目录

扩展查询

前文《[NewLife.XCode]实体类详解》中有讲到扩展查询,XCode生成实体类代码时,在模型类有一个region叫“扩展查询”,一般是FindByAbc/FindAllByAbc的形式。

扩展查询以数据表索引为依据来生成:

  • 唯一索引(含主键)生成FindByAbc方法(如FindByName),返回单个对象;

  • 非唯一索引生成FindAllByAbc方法(如FindAllByClassID),返回对象列表(非null);

640?wx_fmt=png

如上图,可知Entity实体基类内部,查询方法分为单对象查询的Find和对象列表的查询FindAll。

实际上,Find最终调用FindAll方法查一行。

 

Find/FindAll有多个重载,最主要的地方都是构造where查询条件。

下划线_是每个实体类都有的内嵌类,它包含了每一个字段的Field引用,借助运算符重载,可以很方便的构造查询条件,例如上面的_.Name == name最终会生成 where Name='Stone'

640?wx_fmt=png

因为是内嵌类,在实体类内部使用的时候非常方便。但要是想要实体类外部使用,就麻烦很多了,需要带上实体类类名。

 

原则:XCode是充血模型,不管多么简单的查询,建议都封装Find/FindAll/Search等方法供外部使用。

 

回到目录

高级表达式查询

仅靠一两个字段的简单查询,肯定无法满足各种业务要求,我们需要更强大的查询支持,特别是根据不同条件拼接不同语句。

640?wx_fmt=png

640?wx_fmt=png

上面是两个非常典型的业务查询。

这里请出了条件表达式WhereExpression,实际上它只有两个功能,&表示And,|表示Or,根据表达式级别支持括号运算。

exp&=xxx 是最常用的写法,右边一般是各种Field表达式。

上面第一个例子,生成的查询语句可能是 select * from Student where classid=?classid and name like '%?key%'

为什么说“可能”?因为classid为0,或者key为空时,并不会参与拼接查询语句。

 

第二个例子稍微复杂一些,首先对key进行精确查询,找到了就返回,若是没找到,则开启模糊查询。

这里遇到了等于、包含、区间等判断操作,后面会详解所有支持的操作。

 

如非必要,建议保留select * 的查询方式,而不是指定列。

码农法则:数据库压力小于100qps时不要考虑指明select列来优化,大多数系统活不到需要优化的明天!

 

回到目录

高级分页 

两个例子都出现了一个PageParameter参数page,这是分页参数,包含分页查询以及排序所需要的数据。

640?wx_fmt=png

PageIndex和PageSize指定页序号和每页大小,这是内部建立分页查询的核心依据;

Sort 指定排序字段,Desc 指定是否降序(默认升序);

RetrieveTotalCount 指定是否或者总记录数,若为true,则在查询记录集之前,先查询满足条件的总行数TotalCount,用于分页PageCount。此时等于执行两次数据库查询;

RetrieveState 指定是否获取统计 State,若为true,则在查询记录集之后,执行聚合查询,对数字型字段使用Sum聚合。此时最多可能执行3次数据库查询;

在执行FindAll查询时,若有传入 PageParameter 且 RetrieveTotalCount 为true,则先查询满足条件的记录数,大于0时才查某一页数据。

如果 Meta.Count 评估认为本表总行数超过100万,且FindAll查询没带有条件,则page.TotalCount直接取Meta.Count(少量偏差),以避免极大的FindCount耗时。

100万行以上数据表,如若不带条件或者条件没有命中索引,select count 将会极其的慢,在1000万以上甚至查不出来,这是XCode能对100亿表进行分页查询的关键所在

 640?wx_fmt=png

Meta.Count 的初始值来自于数据库元数据索引表,里面有该表主键的总行数,取得该值后如果小于100万再异步select count一次。

10多年前博客园ORM大战的时候,我们常说,等你支持千万级分页的时候再来比,就是钻了select count很慢的这个空子,很多人count出来总数再分页 ^_^

上图4亿数据,查询第10000页,在SQLite单表上,阿里云1C1G服务器。

 

FindCount 分页

在早期版本,不支持RetrieveTotalCount ,只能通过 FindCount 取得满足该条件的总记录数,然后进行分页,至今仍然支持传统方法。

因此可以看到,FindAll 和 FindCount 都是成对出现,参数一摸一样。

并且 FindCount 方法也会带有分页参数,虽然用不到,但.NET2.0时代的 ObjectDataSource 要求两者的参数名称和顺序必须一致。

所有 FindCount 方法,将会得到 select count 查询语句,因此千万级大表需要慎用。

 

PageSplit 分页

内置支持的各种数据库,都有实现普通查询语句转为分页语句的 PageSplit(sql, start, maxNums) 方法。

MySql/SQLite/PostgreSQL 能够很好支持,只需要在 sql 后加上 limit start, maxNums 即可;

Oracle/SqlServer/Access/SqlCe 则要麻烦一次,其中SqlServer最复杂,不同版本的分页方法还不同,早期版本还要求有主键字段;

因此,sql 必须是简单的单表查询语句,PageSplit 才能把任意查询拆开并转换为分页查询。

 

大表分页优化

大表分页查询,开头会很快,越是往后越慢!

XCode采用倒置优化法,对于超过100万行(借助Meta.Count评估)的表,如果查询页超过中线,则从另一个方向查询,然后再把结果倒置回来。

640?wx_fmt=png

 

 

XCode要求数据查询必须考虑分页,没有分页的系统一般死在100万行以内。

 

回到目录

Field扩展

内嵌类_引用的字段是Field,它继承自FieldItem。

Field/FieldItem全部功能:

  • Equal 等于,操作符==

  • NotEqual 不等于,操作符!=

  • 大于操作符>,大于等于>=

  • 小于操作符<,小于等于<=

  • StartsWith 字符串开始,like '{0}%'。(支持索引)

  • EndsWith 字符串结束,like '%{0}'

  • Contains 字符串包含,like '%{0}%'

  • In 集合包含,支持列表集合、字符串子查询和SelectBuilder子查询,集合只有一个元素时转为相等操作

  • NotIn 集合不包含,支持列表集合、字符串子查询和SelectBuilder子查询,集合只有一个元素时转为不相等操作

  • IsNull 是否空

  • NotIsNull 不是空

  • IsNullOrEmpty 字符串空或零长度

  • NotIsNullOrEmpty 字符串非空非零长度

  • IsTrue 是否True或者False/Null,参数决定两组之一

  • IsFalse 是否False或者True/Null,参数决定两组之一

  • Between 时间区间,大于等于开始,小于结束,如果开始结束都只有日期而没有时分秒,则结束加一天,如(2019-04-17,  2019-04-17)查 time>='2019-04-17' and time<2019-04-18'

排序字句/分组聚合

  • Asc,升序

  • Desc,降序。order by name desc

  • GroupBy,分组。group by name

  • As,聚合别名

  • Count,计数

  • Sum,求和

  • Min,最小

  • Max,最大

 

回到目录

查询的本质

查询的本质是五参数版FindAll(where, order, selects, start, maxnums),其它查询方式都由它转化而来!

Entity实体基类封装了各种常用的查询方法:

640?wx_fmt=png

640?wx_fmt=png

640?wx_fmt=png

对于单表查询的XCode来说,五参数版FindAll很容易得到 select [selects] from [table] where [where] order by [order] limit [start], [maxnums] 语句,根据这个理念,FindAll可以支持任意复杂查询!

最终查询语句,由SelectBuilder类承载。

 

回到目录

多表子查询

XCode不支持多表Join关联,这在前面《扩展属性》中提到过。

扩展属性固然可以解决关联多表字段的问题,并且借助缓存性能还不错,但是需要同时在两张表上设置条件的时候,就行不通了。

于是,需要用到高级查询,可以用子查询 来替代,正是前面说到的FieldItem.In扩展。

 

要查询名为“992班”的所有学生,一般这样写:

select * from student s inner join class c on s.classid=c.id where c.name='992班'

XCode从2008年起,就放弃支持多表关联,自然也就不支持这样的写法。

在一般系统里面,班级表数据不多,可以借助实体缓存或者对象缓存:

// Class.FindByName 内部用缓存
var cls = Class.FindByName("992班");
var list = Student.FindAll(Student._.ClassID==cls.ID);
// select * from student where classid=1234

但如果主表从表都是百万级大表,或者从表查询条件比较复杂,缓存就有点难以为继了。

于是有了子查询:

640?wx_fmt=png

调用方法:var list = Student.Search(SexKinds.女, "992班", p);

得到结果:

select * from student where sex=2 and classid in(select id from class where name='992班')

至此,绝大部分多表关联复杂查询语句,可以转化为子查询 !

 

回到目录

系列教程

NewLife.XCode教程系列[2019版]

  1. 增删改查入门。快速展现用法,代码配置连接字符串

  2. 数据模型文件。建立表格字段和索引,名字以及数据类型规范,推荐字段(时间,用户,IP)

  3. 实体类详解。数据类业务类,泛型基类,接口

  4. 功能设置。连接字符串,调试开关,SQL日志,慢日志,参数化,执行超时。代码与配置文件设置,连接字符串局部设置

  5. 反向工程。自动建立数据库数据表

  6. 数据初始化。InitData写入初始化数据

  7. 高级增删改。重载拦截,自增字段,Valid验证,实体模型(时间,用户,IP)

  8. 脏数据。如何产生,怎么利用

  9. 增量累加。高并发统计

  10. 事务处理。单表和多表,不同连接,多种写法

  11. 扩展属性。多表关联,Map映射

  12. 高级查询。复杂条件,分页,自定义扩展FieldItem,查总记录数,查汇总统计

  13. 数据层缓存。Sql缓存,更新机制

  14. 实体缓存。全表整理缓存,更新机制

  15. 对象缓存。字典缓存,适用用户等数据较多场景。

  16. 百亿级性能。字段精炼,索引完备,合理查询,充分利用缓存

  17. 实体工厂。元数据,通用处理程序

  18. 角色权限。Membership

  19. 导入导出。Xml,Json,二进制,网络或文件

  20. 分表分库。常见拆分逻辑

  21. 高级统计。聚合统计,分组统计

  22. 批量写入。批量插入,批量Upsert,异步保存

  23. 实体队列。写入级缓存,提升性能。

  24. 备份同步。备份数据,恢复数据,同步数据

  25. 数据服务。提供RPC接口服务,远程执行查询,例如SQLite网络版

  26. 大数据分析。ETL抽取,调度计算处理,结果持久化

 


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

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

相关文章

cf1556B B. Take Your Places!

cf1556B B. Take Your Places! 题意&#xff1a; 有n个数&#xff0c;你可以将相邻两个数交换&#xff0c;使得奇偶性一样的数不相邻。问最少操作步数 题解&#xff1a; 最终排列无非是&#xff1a;奇&#xff0c;偶&#xff0c;奇…或者偶&#xff0c;奇&#xff0c;偶… …

微软云Azure训练营 | 八城联动,全球盛会

Global Azure Bootcamp是由微软发起、MVP参与组织的全球化学习交流活动。每年会挑选一个特定的时间&#xff0c;在同一天内&#xff0c;全球不同地区将同时开展。2019年全球Azure训练营&#xff08;Global Azure Bootcamp&#xff09;将于2019年4月27日在全球270多个城市同时举…

2021-09-211547G - How Many Paths?

#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <set> using namespace std; typedef long long ll;const int N4e510,M1e610,mod998244353;int h[N],hs[N],e[M],ne[M],idx0; // h 原图 hs新图 v…

cf1556Compressed Bracket Sequence

cf1556Compressed Bracket Sequencex 题意&#xff1a; 给你n个数&#xff0c;奇数位置上的数表示左括号的数量&#xff0c;偶数位置上的数表示右括号的数量。问有多少个[l,r]是满足括号匹配的 题解&#xff1a; 括号匹配也算是经典问题了 直接统计不好计算&#xff0c;我们…

长沙4月21日开发者大会暨.NET社区成立大会活动纪实

活动总结2019年4月21日是一个斜风细雨、微风和煦的美好日子&#xff0c;由长沙.NET技术社区、腾讯云云加社区、微软Azure云技术社区、中国.NET技术社区、长沙柳枝行动、长沙互联网活动基地&#xff08;唐胡子俱乐部&#xff09;等多家单位共同主办的长沙开发者技术大会暨长沙.N…

树上启发式合并 简单例题

U41492 树上数颜色 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <set> #include <vector> #include <queue> using namespace std; typedef long long LL; typedef pair<int,int…

cf1556D. Take a Guess

cf1556D. Take a Guess 题意&#xff1a; 交互题 有n个数和k个询问&#xff0c;你最多只能询问2n次&#xff0c;可以询问任意两个位置数的or或者是and&#xff0c;然后输出这n个数的第k大数 题解&#xff1a; 先说个结论&#xff1a; x y (x or y) (x and y) (嘶&#x…

SQL Server AlwaysOn 集群 关于主Server IP与Listener IP调换的详细测试

1. 背景SQL Server 搭建AlwaysOn后&#xff0c;我们就希望程序连接时使用虚拟的侦听IP&#xff08;Listener IP&#xff09;&#xff0c;而不再是主Server 的IP。如果我们有采用中间件&#xff0c;则可以在配置中&#xff0c;直接用Listener IP 替换掉 Server IP&#xff0c;可…

1592E - Скучающий Бакри

首先把那式子转换成长度为偶数并且二进制有一段连续的一&#xff0c;大于这位的数量都是偶数 如果长度为奇数那么如果 and 是1&#xff0c;xor 一定是1&#xff1b;and 是0&#xff0c;xor可能是1&#xff1b;所以长度为奇数一定不可以。 那么长度为偶数的话&#xff0c;对二…

cf1556E. Equilibrium

cf1556E. Equilibrium 题意&#xff1a; 有a&#xff0c;b两组长度为n的数&#xff0c;现在你要通过操作将范围[l,r]中的a&#xff0c;b两组一样。每次操作你在[l,r]中选偶数个下标pos&#xff0c;{pos1,pos2,pos3…}&#xff0c;在奇数位上的下标给序列a对应的下标pos1加上1…

线段树动态开点 - - - > 线段树合并

逆序对 代码 P3224 [HNOI2012]永无乡 并查集线段树合并 ​​​​ 代码 P5494 【模板】线段树分裂 #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<vector> #include<queue> #include<…

在 DotNetCore 3.0 程序中使用通用协议方式启动文件关联应用

问题描述在传统的基于 .NET Framework 的 WPF 程序中&#xff0c;我们可以使用如下代码段启动相关的默认应用&#xff1a;Copy# 启动默认文本编辑器打开 helloworld.txtProcess.Start("helloworld.txt");# 启动默认浏览器打开 https:Process.Start("https://hip…

cf451E. Devu and Flowers(产生不同多重集数量)

cf451E. Devu and Flowers 题意&#xff1a; 有n个箱子&#xff0c;第i个箱子里有ai朵花&#xff0c;同一个箱子里花的颜色一样&#xff0c;不同箱子里的花颜色不一样。现在在这些箱子里选出m朵花组成一束&#xff0c;求一共有多少种方案。要求任意两束花都不一样 题解&…

.NetCoreLinuxDockerPortainer踩坑历险记

最近有一个云服务器和数据库的迁移任务&#xff0c;踩坑爬坑无数次&#xff0c;觉得必须要记录一下。大家瓜子花生准备好&#xff0c;听我慢慢讲故事#手动笑哭#。故事背景公司是做电商业务的&#xff0c;在天猫有几家旗舰店数据量也很大。阿里有一个称为聚石塔的平台&#xff0…

F - Parenthesis Checking

​​​​​​​1 . ( - > 1 , ) - > -1; 先想前缀和&#xff0c;求出l&#xff0c;r中的最小值&#xff0c;如果最小值小于l-1的前缀和&#xff0c;那么说明有某个点的 ) 大于 ( 数量 不满足条件&#xff1b; 用线段树优化区间修改和区间查询&#xff1b; 2 . …

cf208E. Blood Cousins

cf208E. Blood Cousins 题意&#xff1a; 给你一个森林&#xff0c;m次询问&#xff0c;每次询问(v,p),问v的p-cousin有多少&#xff1f;p-cousin指的是与v在同一层且他们到lca的距离都是p 题解&#xff1a; 对于每次询问(v,p),我们都可以通过其找到v的p距离的父亲节点fa&a…

深入源码理解.NET Core中Startup的注册及运行

开发.NET Core应用&#xff0c;直接映入眼帘的就是Startup类和Program类&#xff0c;它们是.NET Core应用程序的起点。通过使用Startup&#xff0c;可以配置化处理所有向应用程序所做的请求的管道&#xff0c;同时也可以减少.NET应用程序对单一服务器的依赖性&#xff0c;使我们…

并查集虚拟节点

​ HDU 3234 Exclusive-OR AC代码简洁版 AC代码不好看的 Almost Union-Find UVA - 11987 AC代码 #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <sstream> using namespace std; typedef long …

cf246E. Blood Cousins Return

cf246E. Blood Cousins Return 题意&#xff1a; 给你一个森林&#xff0c;每个点都有自己的种类&#xff0c;问以v为根节点的子树中&#xff0c;与v距离为k的节点有多少种 题解&#xff1a; 和cf208E. Blood Cousins这个题差不多&#xff0c;就是多了一个种类&#xff0c;…

Python、Java、TypeScript 和 Perl 作者谈语言设计

Python 作者 Guido van Rossum、Java 作者 James Gosling、Turbo Pascal 和 TypeScript 作者 Anders Hejlsberg&#xff0c;以及 Perl 作者 Larry Wall 本月早些时候齐聚一堂&#xff0c;讨论了(YouTube)编程语言设计的过去和未来。Guido van Rossum 说&#xff0c;设计一种语言…