ShardingCore 如何呈现“完美”分表

  这篇文章是我针对efcore的分表的简单介绍,如果您有以下需求那么可以自己选择是否使用本框架,本框架将一直持续更新下去,并且免费开源为.net生态做贡献,如果您觉得不错那么请帮忙点个star谢谢,框架地址[`sharding-core`](https://github.com/xuejmnet/sharding-core) 您的支持是对我最大的动力。

如果您对分表有以下痛点那么不妨试试我这边开源的框架sharding-core ,是否需要无感知使用分表组件,是否需要支持abp,是否需要支持自定义分表规则,是否需要支持自定义分表键,是否需要支持特定的efcore版本,是否希望框架不带任何三方框架干净,是否需要支持读写分离,是否需要动态添加表,是否需要支持join,group等操作,是否需要支持追踪特性,是否想在不修改原先代码的基础上扩展分表功能,如果一起上几个条件任意组合且你在市面上没办法找到可替代的框架可以试试本框架。如何使用代码具体可以参考github 将代码下载下来如果本地装了sqlserver直接运行单元测试或者Sample.SqlServer程序会自动在本地新建数据库新建数据库表结构,目前初始化数据为用户信息和用户对应的月薪信息表,用户表以用户id取模,用户月薪表以月份分表。

首先需要了解本框架的一个版本号不然将对您的使用产生一定的分歧,目前框架分为3个版本分别是2.x,3.x,5.x3个版本,分别对应efcore 2.x efcore 3.x efcore 5.x,有人要问为什么不支持6.x呢(小弟刚刚在上周完成对本框架的开发重构,目前还未对efcore 6.x进行着手不过将在不远的将来即将支持(目测1-2个星期内))。

目前efcore生态下有着许许多多的分表、分库的解决方案,但是目前来讲都有其不足点,比如需要手动设置分表后缀、需要大量替换现有代码、不支持事务等等一系列问题,所以在这个大前提下我之前开源了sharding-core 分表组件,这个分表组件是目前来说个人认为比较“完美”的分表组件,这个分表组件目前是参考了sharding-jdbc来实现的,但是比sharding-jdbc更加强大(因为C#的表达式)。首先我们来看下目前市面上有的分表组件的缺点我们来针对其缺点进行痛点解决。

efcore支持情况

efcore版本是否支持
2.x支持
3.x支持
5.x支持
6.x即将支持

数据库支持情况

数据库理论是否支持
SqlServer支持
MySql支持
PostgreSql支持
SQLite支持
Oracle支持
其他支持(只要efcore支持)

理论上只要是efcore对应版本支持的数据库,sharding-core都将支持。

如何开始使用

1.创建一个数据库对象继承IShardingTable并且在对应的分表字段上进行[ShardingTableKey]特性的标注

 /// <summary>/// 用户表/// </summary>public class SysUserMod : IShardingTable{/// <summary>/// 用户Id用于分表/// </summary>[ShardingTableKey(TailPrefix = "_")]public string Id { get; set; }/// <summary>/// 用户名称/// </summary>public string Name { get; set; }/// <summary>/// 用户姓名/// </summary>public int Age { get; set; }}

2.创建对应的实体表对应配置 推荐 fluent api

    public class SysTestMap:IEntityTypeConfiguration<SysTest>{public void Configure(EntityTypeBuilder<SysTest> builder){builder.HasKey(o => o.Id);builder.Property(o => o.Id).IsRequired().HasMaxLength(128);builder.Property(o => o.UserId).IsRequired().HasMaxLength(128);builder.ToTable(nameof(SysTest));}}

3.创建对应的分表规则 取模分表,参数2代表后缀2位就是00-99最多100张表,3表示模3== key.hashcode() %3

    public class SysUserModVirtualTableRoute : AbstractSimpleShardingModKeyStringVirtualTableRoute<SysUserMod>{public SysUserModVirtualTableRoute() : base(2,3){}}

4创建对应执行的dbcontext 这一步除了继承IShardingTableDbContext外其他和普通dbcontext一样

public class DefaultTableDbContext: DbContext,IShardingTableDbContext{public DefaultTableDbContext(DbContextOptions<DefaultTableDbContext> options) :base(options){}protected override void OnModelCreating(ModelBuilder modelBuilder){base.OnModelCreating(modelBuilder);modelBuilder.ApplyConfiguration(new SysUserModMap());}public IRouteTail RouteTail { get; set; }}

5.添加分表dbcontext

public class DefaultShardingDbContext:AbstractShardingDbContext<DefaultTableDbContext>{public DefaultShardingDbContext(DbContextOptions<DefaultShardingDbContext> options) : base(options){}protected override void OnModelCreating(ModelBuilder modelBuilder){base.OnModelCreating(modelBuilder);modelBuilder.ApplyConfiguration(new SysUserModMap());}public override Type ShardingDbContextType => this.GetType();}

6.添加配置

        public void ConfigureServices(IServiceCollection services){services.AddControllers();//原先的dbcontext可以用也可以不用如果原先的dbcontext还在用就继续//services.AddDbContext<DefaultTableDbContext>(o => o.UseSqlServer("Data Source=localhost;Initial Catalog=ShardingCoreDBxx3;Integrated Security=True"));services.AddShardingDbContext<DefaultShardingDbContext, DefaultTableDbContext>(o => o.UseSqlServer("Data Source=localhost;Initial Catalog=ShardingCoreDBxx2;Integrated Security=True;"), op =>{op.EnsureCreatedWithOutShardingTable = true;op.CreateShardingTableOnStart = true;op.UseShardingOptionsBuilder((connection, builder) => builder.UseSqlServer(connection).UseLoggerFactory(efLogger),//使用dbconnection创建dbcontext支持事务(conStr,builder) => builder.UseSqlServer(conStr).UseLoggerFactory(efLogger));//使用链接字符串创建dbcontextop.AddShardingTableRoute<SysUserModVirtualTableRoute>();});}public void Configure(IApplicationBuilder app, IWebHostEnvironment env){...//添加启动项app.UseShardingCore();...}public static class ShardingCoreExtension{public static IApplicationBuilder UseShardingCore(this IApplicationBuilder app){var shardingBootstrapper = app.ApplicationServices.GetRequiredService<IShardingBootstrapper>();shardingBootstrapper.Start();return app;}}

7.控制器使用

private readonly DefaultShardingDbContext _defaultTableDbContext;public ValuesController(DefaultShardingDbContext defaultTableDbContext){_defaultTableDbContext = defaultTableDbContext;}[HttpGet]public async Task<IActionResult> Get(){var resultx11231 = await _defaultTableDbContext.Set<SysUserMod>().Where(o => o.Age == 198198).Select(o=>o.Id).ContainsAsync("1981");var resultx1121 = await _defaultTableDbContext.Set<SysUserMod>().Where(o => o.Id == "198").SumAsync(o=>o.Age);var resultx111 = await _defaultTableDbContext.Set<SysUserMod>().FirstOrDefaultAsync(o => o.Id == "198");var resultx2 = await _defaultTableDbContext.Set<SysUserMod>().CountAsync(o => o.Age<=10);var resultx = await _defaultTableDbContext.Set<SysUserMod>().Where(o => o.Id == "198").FirstOrDefaultAsync();var resultx33 = await _defaultTableDbContext.Set<SysUserMod>().Where(o => o.Id == "198").Select(o=>o.Id).FirstOrDefaultAsync();var resulxxt = await _defaultTableDbContext.Set<SysUserMod>().Where(o => o.Id == "198").ToListAsync();var result = await _defaultTableDbContext.Set<SysUserMod>().ToListAsync();var sysUserMod98 = result.FirstOrDefault(o => o.Id == "98");_defaultTableDbContext.Attach(sysUserMod98);sysUserMod98.Name = "name_update"+new Random().Next(1,99)+"_98";await _defaultTableDbContext.SaveChangesAsync();return Ok(result);}

自定义分表键,自定义分表规则

目前市面上有的框架要么对分表字段有限制比如仅支持DateTime类型或者int等,要么对分表规则有限制:仅支持按天、按月、取模...等等,但是基于分表规则和分表字段是业务规则所以本框架遵循将其由业务系统自己定义,最大化来实现分表库的适用性,基本上满足一切分表规则,且sharding-core目前默认提供一些常用的分表规则可以快速集成。

默认路由

抽象abstract路由规则tail索引
AbstractSimpleShardingModKeyIntVirtualTableRoute取模0,1,2...=
AbstractSimpleShardingModKeyStringVirtualTableRoute取模0,1,2...=
AbstractSimpleShardingDayKeyDateTimeVirtualTableRoute按时间yyyyMMdd>,>=,<,<=,=,contains
AbstractSimpleShardingDayKeyLongVirtualTableRoute按时间戳yyyyMMdd>,>=,<,<=,=,contains
AbstractSimpleShardingWeekKeyDateTimeVirtualTableRoute按时间yyyyMMdd_dd>,>=,<,<=,=,contains
AbstractSimpleShardingWeekKeyLongVirtualTableRoute按时间戳yyyyMMdd_dd>,>=,<,<=,=,contains
AbstractSimpleShardingMonthKeyDateTimeVirtualTableRoute按时间yyyyMM>,>=,<,<=,=,contains
AbstractSimpleShardingMonthKeyLongVirtualTableRoute按时间戳yyyyMM>,>=,<,<=,=,contains
AbstractSimpleShardingYearKeyDateTimeVirtualTableRoute按时间yyyy>,>=,<,<=,=,contains
AbstractSimpleShardingYearKeyLongVirtualTableRoute按时间戳yyyy>,>=,<,<=,=,contains

所谓的索引就是通过改对应的条件操作符可以缩小减少指定表的范围,加快程序的执行
如果以上默认分表无法满足您的需求您还可以自定义分表,如何分表可以通过继承 AbstractShardingOperatorVirtualTableRoute<TEntity,TKey>来实现自定义分表规则(近乎90%的规则都可以实现)

动态添加分表信息

很多分表组件默认不带动态分表信息导致很多分表没办法根据业务系统来进行动态创建,sharding-core默认提供动态建表接口可以支持动态按时间,按租户等不需要数据做迁移的动态分表信息,
如果需要请参考Samples.AutoByDate.SqlServer

支持select,join,group by等连表聚合函数

目前sharding-core支持select按需查询,join分表连表查询,group by聚合查询,虽然本框架支持但是出于性能原因本框架还是不建议使用join操作符来操作,因为过多的表路由会导致笛卡尔积,会导致需要查询的表集合增长对数据库连接比较考验。
以下代码来自github的单元测试中,SysUserMod表示用户表,SysUserSalary表示用户月薪表用户表按id取模,用户月薪表按月分表

//join查询
var list = await (from u in _virtualDbContext.Set<SysUserMod>()join salary in _virtualDbContext.Set<SysUserSalary>()on u.Id equals salary.UserIdselect new{u.Id,u.Age,Salary = salary.Salary,DateOfMonth = salary.DateOfMonth,Name = u.Name}).ToListAsync();//group聚合查询
var ids = new[] {"200", "300"};var dateOfMonths = new[] {202111, 202110};var group = await (from u in _virtualDbContext.Set<SysUserSalary>().Where(o => ids.Contains(o.UserId) && dateOfMonths.Contains(o.DateOfMonth))group u by new{UId = u.UserId}into gselect new{GroupUserId = g.Key.UId,Count = g.Count(),TotalSalary = g.Sum(o => o.Salary),AvgSalary = g.Average(o => o.Salary),AvgSalaryDecimal = g.Average(o => o.SalaryDecimal),MinSalary = g.Min(o => o.Salary),MaxSalary = g.Max(o => o.Salary)}).ToListAsync();

分页

我们常说的分页是分表的难点也是最考验分表组件的
1我们首先来看普通的分表组件如何分页
首先我们定义一组组数据比如是1-100的连续数字,然后分成两张表按奇偶分表

表名数据
table11,3,5,7,9...
table22,4,6,8,10...
select * from table limit 2,2理论上结果3,4 
如果本次查询会做落到table1 和table2那么会改写成 2句sql 
第一句 select * from table1 limit 4 ---> 1,3,5,7
第二句 select * from table2 limit 4 ---> 2,4,6,8
将8条数据放入内存然后排序
1,2,3,4,5,6,7,8
获取第3到4条数据 结果[3,4]

这个情况是我们常见的也是最简单的分页,但是这个情况仅仅适用于数据量小的时候,如果用户不小心点到了分页的最后一页那么结果将是灾难性的这是毋庸置疑的
那么sharding-core是如何处理的呢

select * from table limit 2,2
首先还是一样对数据库语句进行改性并且生成对应的sql
第一句 select * from table1 limit 4 
第二句 select * from table2 limit 4
因为ado.net默认DataReader是流式获取,只要连接不关闭那么可以一直实现next获取到内存
创建一个优先级队列一个可以具有排序功能的队列
因为DataReader的特性我们分别对sql1和sql2进行一次next获取到2个数组一个是[1,.....] A和数组[2......] B
获取到两个数组我们只知道头部第一个对象因为没有进行后续的next所以无法知晓剩下的数据但是有一点可以知道后面的数据都是按sql的指定顺序的所以都不会比当前头大或者小
先将1和2放入优先级队列可以知道如果asc那么数组A放在队列头 数组B放在队列尾部,然后对优先级队列进行poll弹出,并且对A进行next这个时候A变成了[3,....]再将A放入优先级队列
这时候优先级队列就是B在前A在后依次操作,然后对分页的进行过滤因为要跳过2个对象所以只需要空执行2次那么指针就会指向A数组的3和B数组的4,剩下的只要获取2个数据就可以了,
这样做可以保证内存最小化,然后分页不会成为程序的灾难。

无感知使用

目前的分表框架很少有做到无感知使用的,你在使用的时候好一点的框架不依赖三方,一般一点的不但要依赖很多三方框架并且在使用的时候还有一大堆限制,必须使用他的东西还没办法做到和dbcontext原生的使用方法。
sharding-core目前使用的是一种类似dbcontext的wrap模式,用一个新的dbcontext来包装真实的dbcontext,这个包装的dbcontext我们成为shardingdbcontext,shardingDbContext因为本身也是集成于DbContext所以它的使用方法和原生dbcontext没有差别。并且仅需少量改动即可支持abp和abp.next

读写分离的支持

目前sharding-core已经支持单node节点的读写分离操作,将在不久的未来(1-2)天内支持多节点的读写分离

services.AddShardingDbContext<ShardingDefaultDbContext, DefaultDbContext>(o => o.UseSqlServer(hostBuilderContext.Configuration.GetSection("SqlServer")["ConnectionString"]),op =>{op.EnsureCreatedWithOutShardingTable = true;op.CreateShardingTableOnStart = true;op.UseShardingOptionsBuilder((connection, builder) => builder.UseSqlServer(connection).UseLoggerFactory(efLogger),(conStr,builder)=> builder.UseSqlServer("read db connection string").UseLoggerFactory(efLogger));op.AddShardingTableRoute<SysUserModVirtualTableRoute>();op.AddShardingTableRoute<SysUserSalaryVirtualTableRoute>();});

未来计划将支持分库,支持强制路由,显示路由等...
最后具体如何使用且使用方式可以参考github(https://github.com/xuejmnet/sharding-core) 当然我也会在后续出一系列的博客来对框架进行支持的介绍

最后的最后

该文档是我晚上赶工赶出来的也想趁热打铁希望更多的人关注,也希望更多的人可以交流。

凭借各大开源生态圈提供的优秀代码和思路才有的这个框架,希望可以为.Net生态提供一份微薄之力,该框架本人会一直长期维护,有大神技术支持可以联系下方方式欢迎star ????

博客

QQ群:771630778

个人QQ:326308290(欢迎技术支持提供您宝贵的意见)

个人邮箱:326308290@qq.com

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

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

相关文章

使用javascript oop开发滑动(slide) 菜单控件

这里使用原生的javascript&#xff0c;用面向对象的方式创建一个容易维护使用方便的滑动菜单&#xff0c;调用方式如下&#xff1a;var$sliding document.getElementById("silding");vars1 newSliding();s1.commands $sliding.getElementsByTagName("dt");…

他毕业于北师大,编写了我国首套数学教材,陈景润华罗庚都崇拜他

全世界只有3.14 % 的人关注了爆炸吧知识要说起我国著名的数学家&#xff0c;很多人会想到陈景润、华罗庚等人&#xff0c;这些大数学家为我国数学研究做出了卓越贡献&#xff0c;也深深影响了很多人。那么&#xff0c;像陈景润、华罗庚这些大数学家&#xff0c;他们学习数学有受…

用多媒体库 Bass.dll 播放 mp3 [8] - 实时显示左右声道的峰值

为什么80%的码农都做不了架构师&#xff1f;>>> 本例效果图: 代码文件: unit Unit1;interfaceusesWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs, StdCtrls, ExtCtrls, ComCtrls;typeTForm1 class(TForm)OpenDialog1: TOpe…

最近看了两本低代码的书

月初写了一篇《你真的了解低代码平台吗&#xff1f;》&#xff0c;介绍了下我对低代码产品的一些认识&#xff0c;随后有朋友送了我两本华章出版的关于低代码的书&#xff1a;明道云的《零代码实战》和微软的《实战低代码》&#xff0c;目前市面上也就这两本关于低代码的书。因…

如何逼疯一名数学系学生?

全世界只有3.14 % 的人关注了爆炸吧知识今天在知乎竟看到这样一个问题但看在关注人数如此之多超模君就放下成见稍微透露一下我们的“底线”到底要怎样做才能激怒数学系学生数学沾边法顾名思义只要和数学沾边就可以开怼在菜市场算菜钱时在提问后的0.5秒迅速补上致命一刀经过彩票…

WinAPI: 钩子回调函数之 MouseProc

为什么80%的码农都做不了架构师&#xff1f;>>> MouseProc(nCode: Integer; {}wParam: WPARAM; {}lParam: LPARAM {} ): LRESULT; {}//待续...转载于:https://my.oschina.net/hermer/blog/320962

内推!字节、阿里、网易火热招聘中,内推优筛简历,快人一步拿offer,真香!(送内推码)...

全世界只有3.14 % 的人关注了爆炸吧知识“金三银四”可谓招聘的黄金期。一方面&#xff0c;校园春招正如火如荼的进行中&#xff0c;另一方面&#xff0c;各大企业也纷纷启动了暑假实习招聘。对于2020届的同学来说&#xff0c;务必要利用好“应届生”这个身份&#xff0c;把握住…

如何将10进制转成16进制,又如何将16进制数转成10进制,C#和VB代码?

方法1&#xff1a; int d10; d.ToString("x") //或把x改为&#xff38;&#xff0c;&#xff0c;&#xff0c;就变成了&#xff11;&#xff16;位的字符串了&#xff0e; int xConvert.ToInt32(d.ToString("x"),16);&#xff0f;&a…

本科4篇顶会论文如何做到?清华特奖高天宇干货分享:我是这样写论文、做实验、与导师相处...

全世界只有3.14 % 的人关注了爆炸吧知识本科生&#xff0c;距离“科研”有多远&#xff1f;有人还处在“小朋友你是否有很多问号”的状态&#xff0c;但也有人本科就连发顶会文章&#xff0c;光环闪瞎众人。其中可有什么秘诀&#xff1f;清华本科特奖获得者、清华计算机大四学生…

java final 修改_“无法改变的设计”——浅谈Java中的final关键字

在Java中&#xff0c;final关键字可以用来修饰类、变量(包括成员变量和局部变量)、方法&#xff0c;下面从这三个方面分别说明。final方法当一个方法被final修饰时&#xff0c;表明这个方法不能被子类重写。下面程序试图重写final方法&#xff0c;将会引发编译错误。public cla…

一致性 hash 算法( consistent hashing )

consistent hashing 算法早在 1997 年就在论文 Consistent hashing and random trees 中被提出&#xff0c;目前在cache 系统中应用越来越广泛&#xff1b; 1 基本场景 比如你有 N 个 cache 服务器&#xff08;后面简称 cache &#xff09;&#xff0c;那么如何将一个对象 obje…

复工之后,如何让自己的时间更值钱

全世界只有3.14 % 的人关注了爆炸吧知识时间最不偏私给任何人都是二十四小时时间也最偏私给任何人都不是二十四小时而如何让自己的时间更值钱以下公众号或许能给你一些启示赶快扫码关注吧&#xff01;RSS精选ID&#xff1a;KindleNewsRSS精选是一个专注于时间管理iOS相关及Kind…

selenium autoit java_Java+Selenium——AutoIt工具处理文件上传

关于文件上传&#xff0c;这边介绍一个第三方工具&#xff0c;叫AutoIt&#xff0c;简单来说&#xff0c;这个是一个能支持桌面GUI自动化的工具&#xff0c;它支持脚本语言编写。这里&#xff0c;我们用AutoIt来做文件上传的演示。在Selenium脚本中如果需要AutoIt来协助这个文件…

Blazor+Dapr+K8s微服务之开发环境调试

1 安装Dapr开发调试环境1.1 Dapr 完整安装模式不支持开发调试在上一篇随笔《BlazorDaprK8s微服务之服务调用》中&#xff0c;我们通过为每个微服务运行dapr run ….dotnet run命令&#xff0c;以自宿主的方式在本地开发环境成功运行了服务调用的例子。但是&#xff0c;这种运行…

这10个人,总是牛逼的无话可说

全世界只有3.14 % 的人关注了爆炸吧知识终于迎来知识君最喜欢的工作日了。热爱工作的知识君还是在认真地看书&#xff0c;码字。哈哈哈&#xff0c;有模友知道看得是什么书然而在拍完照片后&#xff0c;还是得想想今晚该写些啥东西。狄拉克 保罗狄拉克(Paul Adrien Maurice …

WebSocket服务器(物联网下行通知神器)

HttpServer是一个轻量级Web服务器&#xff0c;用于在嵌入式设备以及客户端环境中提供简单Web服务&#xff0c;同时也支持标准WebSocket服务。本文例程基于vs2022&#xff0c;基础例程可参考&#xff1a;https://www.yuque.com/smartstone/nx/httpserverWebSocket服务端WebSocke…

继续送假期干货——响应式图片工具smartImg

中午看《众妙之门》看到一个响应式图片处理工具&#xff08;点此查看&#xff09;的介绍&#xff0c;然后就心血来潮想着不妨自己写一个基于JQ的吧&#xff0c;于是就又有了这么一个干货给大家。 smartImg 的全部文件可以从我的Github上下载&#xff0c;其实它非常小巧&#xf…

一顿家庭火锅让本不富裕的家庭雪上加霜......

1 从此再也没有人相信你曾是个双眼皮▼2 在家吃火锅让一个本不富裕的家庭雪上加霜▼3 大型翻车现场▼4 各位大爷大伯&#xff0c;我先干了招待不周&#xff0c;还望海涵▼5 老外为了防止用手摸脸导致传染发明出来的新方法 ......但这东西难道不是宠物那啥用的吗&#xff1…

ASP.NET Core 修改开源协议为MIT,.NET全平台 MIT协议开源了

2021年7月23日&#xff0c;.NET开发团队完成了所有的.NET平台的相关框架的MIT协议更改&#xff0c;我们可以通过 https://github.com/dotnet/aspnetcore/issues/18873 看到详细的修改提交&#xff0c;这个协议修改里面主要有2点&#xff0c;具体可以看 https://github.com/dotn…

InstallSield更新包快速入门文档----感谢原作者ㄣ齊¨彡仯乄的无私提供

本文经原作者ㄣ齊彡仯乄特许授权于海洋女神发布&#xff0c;转载请务必注明出处与链接&#xff1b;原作者ㄣ齊彡仯乄和海洋女神保留对该文的一切法律许可下的权益&#xff1b;需要发布在盈利性报刊、网站等请与原作者ㄣ齊彡仯乄或海洋女神联系. 简述 本文主要描述安装程序更新包…