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慢吗?

系列教程

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抽取,调度计算处理,结果持久化

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

  1. Hive中小表与大表关联(join)的性能分析【转】

    Hive中小表与大表关联(join)的性能分析 [转自:http://blog.sina.com.cn/s/blog_6ff05a2c01016j7n.html] 经常看到一些Hive优化的建议中说当 ...

  2. [NewLife.XCode]反向工程(自动建表建库大杀器)

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

  3. SQL学习(五)多表关联-join

    在实际工作中会用到多表联查,此时需要用到关键字JOIN 一.inner join(内连接) 至少有一个匹配时返回行,只返回两个表中连接字段相等的行 如: select * from ticket in ...

  4. [NewLife.XCode]分表分库(百亿级大数据存储)

    NewLife.XCode是一个有15年历史的开源数据中间件,支持netcore/net45/net40,由新生命团队(2002~2019)开发完成并维护至今,以下简称XCode. 整个系列教程会大量 ...

  5. [NewLife.XCode]数据模型文件

    NewLife.XCode是一个有10多年历史的开源数据中间件,由新生命团队(2002~2019)开发完成并维护至今,以下简称XCode. 整个系列教程会大量结合示例代码和运行日志来进行深入分析,蕴含 ...

  6. [NewLife.XCode]实体类详解

    NewLife.XCode是一个有10多年历史的开源数据中间件,由新生命团队(2002~2019)开发完成并维护至今,以下简称XCode. 整个系列教程会大量结合示例代码和运行日志来进行深入分析,蕴含 ...

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

    NewLife.XCode是一个有10多年历史的开源数据中间件,支持nfx/netcore,由新生命团队(2002~2019)开发完成并维护至今,以下简称XCode. 整个系列教程会大量结合示例代码和 ...

  8. [NewLife.XCode]对象字典缓存(百万军中取敌首级)

    NewLife.XCode是一个有10多年历史的开源数据中间件,支持nfx/netcore,由新生命团队(2002~2019)开发完成并维护至今,以下简称XCode. 整个系列教程会大量结合示例代码和 ...

  9. [NewLife.XCode]高级增删改

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

随机推荐

  1. H5新特性-视频,音频-Flash-canvas绘图

    json格式 json - > AJAX json:数据格式,通常是以字符串形式表示 对象 {"name":"james","age" ...

  2. LOJ-10092(最大半连通子图)

    题目连通:传送门 思路: 题目定义很清晰,然后就不会了QAQ…… 后来看了书,先缩点,然后再用拓扑排序找到最长的链子的节点数(因为缩点后所有点都是一个强连通分量,所以找最长的链子就是最大限度包含 点的 ...

  3. php类自动加载

    __autoload 新建一个index.php <?php $d = new z(); function __autoload($class) //自动捕获new的类名 { $file = $ ...

  4. switch_root vs pivot_root vs chroot【转】

    1. pivot_root can/should be used together with chroot pivot_root new_root put_old pivot_root moves t ...

  5. java开发师笔试面试每日8题(1)

    1.一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制? 可以有多个类,但只能有一个public的类,并且public的类名必须与文件名相一致. 2.使用fin ...

  6. scrum冲刺

    小组第一次冲刺任务及其完成情况描述: 这次主要是先构建一个框架,然后就是完成首页的一些代码编写,能够基本实现首页的注册.登陆以及一些之后完成的内部构建. 在第一次冲刺任务中的收获和体会,以后如何改进的 ...

  7. ubuntu系统用docker搭建wordpress

    目标:在docker中搭建wordpress 安装顺序: 首先要有一个云服务器---购买或者自己搭建(本人是自己在主机上装了虚拟机,搭建了一个ubuntu14.04,安装链接:https://www. ...

  8. vue.js 2.0(1)

    1.点击一个按钮打开,关闭弹框 2.实现滚动监听,导航看顶置,实现某元素吸顶 路由

  9. Think in java(1)

      OOP编程思想认为万事万物皆对象,而在设计类(class)的时候,就是从我们生活中或者某些事物中抽象出一个具有共同属性,共同行为的描述(类).在实际的开发中,我们一般会不自觉的这样做:假设有一个人 ...

  10. PSR-PHP开发规范(本文版权归作者:luluyrt@163.com)

    遵循PSR-4的自动加载 一.简介 首先这里要了解PSR,Proposing a Standards Recommendation(提出标准建议)的缩写,就是一种PHP开发规范,让我们研发出来的代码更 ...