专栏首页智能大石头[NewLife.XCode]扩展属性(替代多表关联Join提升性能)

[NewLife.XCode]扩展属性(替代多表关联Join提升性能)

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

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

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

为何需要扩展属性

XCode不支持多表关联查询,单表查询利于优化以及分表分库,一切Join都可以借助扩展属性实现,配合缓存使用可以达到更好的效果!

(XCode前期支持多表关联,直到2008年才正式废除)

“扩展属性”是2007年起XCode特有叫法,不同于其它任何场景的意义(如Silverlight/WPF)

前文《实体类详解》中有提到一个学生班级的实体类模型,一个典型需求是查询学生列表时希望暂时班级名称或者其它信息。于是有:

select s.*, c.name where student s left join class c on s.classid=c.id

sql语法千变万化,如果要支持多表关联join,就很难做到统一查询风格,更是难以优化。

于是XCode放弃支持多表关联,宁可拆分为多次查询。令人惊讶的是,不仅性能没有下降,反而大大提升了,主要因为单表小查询有多级缓存的加持!

扩展属性用法

使用扩展属性来实现关联查询,本质上就是多次查询!

如上,这是一个经典的多表关联场景,学生表带有班级ID字段,同样还有产品和分类表等等。

这是XCode根据模型文件自动生成的代码,因为字段名ClassID刚好是Class表加上它的主键ID,并且都是整型。

对于实体对象来说,student.Name是学生名称,student.ClassName是班级名称。

看起来它们就像是一张表的属性字段,这就是扩展属性的由来,不仅仅是多表关联属性,还可以是其它属性,为区别于数据字段属性,统称为扩展属性!

扩展属性先准备一个Class属性,再加一个ClassName,主要是为了方便某些场合使用 student.Class。

当然,执行一次查询得到student后,不论是访问student.Class还是访问student.ClassName,都会触发一次Class.FindByID,可以理解为执行一次查询(不一定是数据库)。

在Web页面上,如果每页显示20个学生,那么先要执行 select * from student limit 20,然后展示学生列表时,因为需要班级名称,触发扩展属性查询。

可以认为,理论上这个页面需要查询1+20次。

扩展属性为什么不写成 public Class Class => Class.FindByID(ClassID) 呢?

其实虽然看起来简单,但是还得考虑一个可能,同一个student对象可能多次访问student.ClassName,这么写岂不是每次访问都会执行Class.FindByID?

因此,XCode设计了扩展集合Extends,可以认为是一个字典,每个扩展属性都经过它走一遭,如果查询过一次就缓存起来,避免反复查询。

Extends.Get第一个属性是扩展属性名,决定是否有缓存,第二个是没有缓存时要执行的委托。

这就是扩展属性缓存,默认缓存时间10秒,足够抗住短期内成千上万次重复调用。

扩展属性优化

尽管有Extends扩展属性缓存支持,但每个对象还是要执行一次Class.FindByID查询,损耗还是不小的。

在XCode里面,根据主键而设计的查询(如FindByID)往往带有很好的缓存优化。

如上,这是XCode默认生成的代码,当Class表数据不足1000行时,走实体缓存。

也就是说,Meta.Cache时执行一次 select * from student 返回所有行,并缓存起来。后面的Find实际上是在缓存中查找。实体缓存有效期默认10秒。

只有数据表达到1000行,才走 Find(_.ID==id) 数据库查询 select * from class where id=? 。然而XCode下层还有一个数据层缓存,相同select查询默认缓存10秒

此外,也可以根据业务特点采用单对象缓存,例如跨境电商的产品种类特别多(10万+),可以采用字典式的单对象缓存。

因此,在学生类那边看起来访问属性会触发多次Class.FindByID,殊不知它内部别有洞天,三级缓存(实体缓存、对象缓存、数据缓存)等着伺候!(后续专文介绍缓存)

回到开头的例子,一个列表页显示20个学生,理论查询次数1+20次,在多级缓存加持的扩展属性下,99.99%的时候只会查询1次,而班级表的关联,完全在内存缓存中进行。

一次简单的单表查询,显然要比join班级表的查询要快得多!

魔方的特别支持

在上述扩展属性中,注意到ClassName属性上有一个Map特性。

它表示映射,本对象的ClassID字段,映射到Class类的ID字段。

在魔方列表页中,本来显示冷冰冰ClassID的地方,就会变为显示友好的ClassName。

在魔方表单页中,本来显示数字框ClassID的地方,也会变成显示下拉列表框。

如果下拉列表库内容很多,可以精简Map特性,只要第一个参数指明本地字段,而不需要第二第三字段表示的目标字段。此时在魔方表单页会显示数字框,但是后面显示ClassName

到此,你还认为多次查询一定比单次Join慢吗?

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

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

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

    大石头
  • [NewLife.XCode]数据层缓存(网站性能翻10倍)

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

    大石头
  • 每天4亿行SQLite订单大数据测试(源码)

    SQLite作为嵌入式数据库的翘楚,广受欢迎! 新生命团队自2010年以来,投入大量精力对SQLite进行学习研究,成功应用于各系统非致命数据场合。

    大石头
  • 腾讯“互联网+”指数·黑龙江篇(2015年第一期)

    ?  1.腾讯“互联网+”指数及其代表意义   在宏观经济领域,为了能客观、快速地了解经济运行及发展趋势,我们往往会采用一些指标、指数对经济现状进行描述。这...

    腾讯研究院
  • 这13项技能让你从传统“撕”到互联网,论Java转型之不易(内含福利)

    本人从传统外企转型到互联网已有3个年头,近两年来面试了很多来自传统行业的同行们。发现他们都有意走进处于风口的互联网,但是由于传统行业使用的技术栈与互联网的有所不...

    养码场
  • 010.多线程-线程间通信

    安全问题: 当线程在读取资源的过程中,写线程操作了资源, 导致读线程读取的数据,一部分是写之前的数据,一部分是写之后的数据。

    qubianzhong
  • 腾讯高级副总裁郭凯天做客北大讲堂,谈腾讯与“互联网+”

    9月26日,腾讯高级副总裁郭凯天做客北大讲堂,围绕“互联网+”与腾讯发展战略进行了主题演讲。郭凯天表示,互联网正逐渐成为社会的基础设施,如水和电一样,融入各...

    腾讯研究院
  • 一条SQL语句在MySQL中如何执行的

    本篇文章会分析一个 sql 语句在 MySQL 中的执行流程,包括 sql 的查询在 MySQL 内部会怎么流转,sql 语句的更新是怎么完成的。

    帅地
  • 每天4亿行SQLite订单大数据测试(源码)

    SQLite作为嵌入式数据库的翘楚,广受欢迎! 新生命团队自2010年以来,投入大量精力对SQLite进行学习研究,成功应用于各系统非致命数据场合。

    大石头
  • 一篇秒懂mycat

    哈喽,大家好,最近换了工作,为了更快的熟悉新环境,大部分精力都在学习公司的项目业务以及技术,所以公众号更新就少了(非常感谢各位依旧关注),但是我又学到了一些新的...

    用户3467126

扫码关注云+社区

领取腾讯云代金券