前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >基于efcore的分表组件开源

基于efcore的分表组件开源

作者头像
呆呆
修改2021-10-09 10:10:55
7980
修改2021-10-09 10:10:55
举报
文章被收录于专栏:centosDai

ShardingCore

ShardingCore 是一个支持efcore 2.x 3.x 5.x的一个对于数据库分表的一个简易扩展,当然也支持不分表的普通使用,.Net下并没有类似mycat或者sharding-jdbc之类的开源组件或者说有但是并没有非常适用的或者说个人在用过后有一些地方因为限制没法很好使用所以决定自己开发这个库,目前该库暂未支持分库(未来会支持),仅支持分表,该项目的理念是让你可以已最少的代码量来实现自动分表的实现,经过多个开源项目的摸索参考目前正式开源本项目 项目地址 github 喜欢的朋友可以点下star Thanks♪(・ω・)ノ

依赖

Release

EF Core

.NET Standard

.NET (Core)

Sql Server

Pomelo.EntityFrameworkCore.MySql

5.x.x.x

>= 5.0.x

2.1

3.0+

>= 2012

5.0.0-alpha.2

3.x.x.x

3.1.10

2.0

2.0+

>= 2012

3.2.4

2.x.x.x

2.2.6

2.0

2.0+

>= 2008

2.2.6

开始

以下所有例子都以Sql Server为例 MySql亦如此

简介

目前该库处于初期阶段,有很多bug也希望各位多多理解,一起努力为.net生态做出一份微薄之力,目前该库支持的分表可以进行完全的自定义,基本上可以满足95%以上的 业务需求,唯一的限制就是分表规则必须满足 x+y+z,x表示固定的表名,y表示固定的表名和表后缀之间的联系(可以为空),z表示表后缀,可以按照你自己的任意业务逻辑进行切分, 如:user_0,user_1或者user202101,user202102...当然该库同样适用于多租户模式下的隔离,该库为了支持之后的分库已经重写了之前的union all查询模式,并且支持多种api, 支持多种查询包括join,group by,max,count,min,avg,sum ...等一系列查询,之后可能会添加更多支持,目前该库的使用非常简单,基本上就是针对IQueryable的扩展,为了保证 该库的简介目前仅使用该库无法或者说难以实现自动建表,但是只需要配合定时任务该库即可完成24小时无人看管自动管理。该库提供了 IShardingTableCreator 作为建表的依赖,如果需要可以参考 按天自动建表

概念

本库的几个简单的核心概念:

  • [Tail] 尾巴、后缀物理表的后缀
  • [TailPrefix] 尾巴前缀虚拟表和物理表的后缀中间的字符
  • [物理表] 顾名思义就是数据库对应的实际表信息,表名(tablename+ tailprefix+ tail) IPhysicTable
  • [虚拟表] 虚拟表就是系统将所有的物理表在系统里面进行抽象的一个总表对应到程序就是一个entityIVirtualTable
  • [虚拟路由] 虚拟路由就是联系虚拟表和物理表的中间介质,虚拟表在整个程序中只有一份,那么程序如何知道要查询系统哪一张表呢,最简单的方式就是通过虚拟表对应的路由IVirtualRoute ,由于基本上所有的路由都是和业务逻辑相关的所以虚拟路由由用户自己实现,该框架提供一个高级抽象

优点

  • [支持自定义分表规则]
  • [支持任意类型分表key]
  • [针对iqueryable的扩展方便使用]
  • [支持分表下的连表] join
  • [支持针对批处理的使用] BulkInsert、BulkUpdate、BulkDelete
  • [提供多种默认分表规则路由] 按时间按取模,自定义(AbstractShardingOperatorVirtualRoute<T, TKey>)
  • [针对分页进行优化] 大页数跳转支持低内存流式处理

缺点

  • [暂不支持分库(不久后会支持)]
  • [消耗连接]出现分表与分表对象进行join如果条件没法索引到具体表会生成笛卡尔积导致连接数爆炸,后期会进行针对该情况的配置
  • [该库比较年轻] 可能会有一系列bug或者单元测试不到位的情况,但是只要你在群里或者提了issues我会尽快解决

安装

代码语言:javascript
复制
<PackageReference Include="ShardingCore.SqlServer" Version="5.0.0.4" />

配置

配置entity 推荐 fluent api 可以实现自动建表功能 IShardingEntity数据库对象必须继承该接口 ShardingKey分表字段需要使用该特性

代码语言:javascript
复制
    public class SysUserMod:IShardingEntity
    {
        /// <summary>
        /// 用户Id用于分表
        /// </summary>
        [ShardingKey]
        public string Id { get; set; }
        /// <summary>
        /// 用户名称
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// 用户姓名
        /// </summary>
        public int Age { get; set; }
    }
    
    public class SysUserModMap:IEntityTypeConfiguration<SysUserMod>
    {
        public void Configure(EntityTypeBuilder<SysUserMod> builder)
        {
            builder.HasKey(o => o.Id);
            builder.Property(o => o.Id).IsRequired().HasMaxLength(128);
            builder.Property(o => o.Name).HasMaxLength(128);
            builder.ToTable(nameof(SysUserMod));
        }
    }

创建virtual route 实现 AbstractShardingOperatorVirtualRoute<T, TKey> 抽象,或者实现系统默认的虚拟路由 框架默认有提供几个简单的路由 默认路由

代码语言:javascript
复制
    public class SysUserModVirtualRoute : AbstractSimpleShardingModKeyStringVirtualRoute<SysUserMod>
    {
        public SysUserModVirtualRoute() : base(3)
        {
        }
    }
  • GetAllTails 现在数据库已存在的尾巴有哪些

Startup.cs 下的 ConfigureServices(IServiceCollection services)

代码语言:javascript
复制
 services.AddShardingSqlServer(o =>
  {
      o.ConnectionString = "";
      o.AddSharding<SysUserModVirtualRoute>();
      o.UseShardingCoreConfig((provider, config) =>
      {
          //如果是development就判断并且新建数据库如果不存在的话(ishardingentity不会被创建)
          config.EnsureCreated = provider.GetService<IHostEnvironment>().IsDevelopment();
          //ishardingentity表是否需要在启动时创建(如果已创建可以选择不创建)
          config.CreateShardingTableOnStart = true;
      });
  });

Startup.cs 下的 Configure(IApplicationBuilder app, IWebHostEnvironment env) 你也可以自行封装app.UseShardingCore()

代码语言:javascript
复制
            var shardingBootstrapper = app.ApplicationServices.GetRequiredService<IShardingBootstrapper>();
            shardingBootstrapper.Start();

使用

代码语言:javascript
复制
        private readonly IVirtualDbContext _virtualDbContext;

        public ctor(IVirtualDbContext virtualDbContext)
        {
            _virtualDbContext = virtualDbContext;
        }

        public async Task ToList_All()
        {
             //查询list集合
            var all=await _virtualDbContext.Set<SysUserMod>().ToShardingListAsync();
            //链接查询
            var list = await (from u in _virtualDbContext.Set<SysUserMod>()
                join salary in _virtualDbContext.Set<SysUserSalary>()
                    on u.Id equals salary.UserId
                select new
                {
                    Salary = salary.Salary,
                    DateOfMonth = salary.DateOfMonth,
                    Name = u.Name
                }).ToShardingListAsync();
            //聚合查询
            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 g
                select new
                {
                    GroupUserId = g.Key.UId,
                    Count = g.Count(),
                    TotalSalary = g.Sum(o => o.Salary),
                    AvgSalary = g.Average(o => o.Salary),
                    MinSalary = g.Min(o => o.Salary),
                    MaxSalary = g.Max(o => o.Salary)
                }).ToShardingListAsync();
        }

更多操作可以参考单元测试

Api

方法

Method

SqlServer Unit Test

MySql Unit Test

获取集合

ToShardingListAsync

yes

yes

第一条

ShardingFirstOrDefaultAsync

yes

yes

最大

ShardingMaxAsync

yes

yes

最小

ShardingMinAsync

yes

yes

是否存在

ShardingAnyAsync

yes

yes

分页

ToShardingPageResultAsync

yes

yes

数目

ShardingCountAsync

yes

yes

求和

ShardingSumAsync

yes

yes

分组

ShardingGroupByAsync

yes

yes

默认路由

抽象abstract

路由规则

tail

索引

AbstractSimpleShardingModKeyIntVirtualRoute

取模

0,1,2...

=

AbstractSimpleShardingModKeyStringVirtualRoute

取模

0,1,2...

=

AbstractSimpleShardingDayKeyDateTimeVirtualRoute

按时间

yyyyMMdd

>,>=,<,<=,=,contains

AbstractSimpleShardingDayKeyLongVirtualRoute

按时间戳

yyyyMMdd

>,>=,<,<=,=,contains

AbstractSimpleShardingWeekKeyDateTimeVirtualRoute

按时间

yyyyMMdd_dd

>,>=,<,<=,=,contains

AbstractSimpleShardingWeekKeyLongVirtualRoute

按时间戳

yyyyMMdd_dd

>,>=,<,<=,=,contains

AbstractSimpleShardingMonthKeyDateTimeVirtualRoute

按时间

yyyyMM

>,>=,<,<=,=,contains

AbstractSimpleShardingMonthKeyLongVirtualRoute

按时间戳

yyyyMM

>,>=,<,<=,=,contains

AbstractSimpleShardingYearKeyDateTimeVirtualRoute

按时间

yyyy

>,>=,<,<=,=,contains

AbstractSimpleShardingYearKeyLongVirtualRoute

按时间戳

yyyy

>,>=,<,<=,=,contains

注:contains表示为o=>ids.contains(o.shardingkey)

高级

批量操作

批量操作将对应的dbcontext和数据进行分离由用户自己选择第三方框架比如zzz进行批量操作或者batchextension

代码语言:javascript
复制
 virtualDbContext.BulkInsert<SysUserMod>(new List<SysUserMod>())
.BatchGroups.ForEach(pair =>
{
    ///zzz or other
    pair.Key.BlukInsert(pair.Value);
});
var shardingBatchUpdateEntry = virtualDbContext.BulkUpdate<SysUserMod>(o => o.Id == "1", o => new SysUserMod()
{
Name = "name_01"
});
shardingBatchUpdateEntry.DbContexts.ForEach(context =>
{
//zzz or other
context.Where(shardingBatchUpdateEntry.Where).Update(shardingBatchUpdateEntry.UpdateExp);
});

手动路由

代码语言:javascript
复制
        var shardingQueryable = _virtualDbContext.Set<SysUserMod>().AsSharding();
        //禁用自动路由
        shardingQueryable.DisableAutoRouteParse();
        //添加路由直接查询尾巴0的表
        shardingQueryable.AddManualRoute<SysUserMod>("0");
        //添加路由针对该条件的路由
        shardingQueryable.AddManualRoute<SysUserMod>(o=>o.Id=="100");
        var list=await shardingQueryable.ToListAsync();

自动建表

参考

事务

默认savechanges支持事务如果需要where.update需要手动开启事务

代码语言:javascript
复制
            _virtualDbContext.BeginTransaction();
            var shardingBatchUpdateEntry = _virtualDbContext.BulkUpdate<SysUserMod>(o=>o.Id=="123",o=>new SysUserMod()
            {
                Name = "name_modify"
            });
            foreach (var dbContext in shardingBatchUpdateEntry.DbContexts)
            {
             //zzz or other batch   
            }
            await  _virtualDbContext.SaveChangesAsync();

注意事项

该库的IVirtualDbContext.Set使用asnotracking所以基本不支持跟踪,目前框架采用AppDomain.CurrentDomain.GetAssemblies(); 可能会导致程序集未被加载所以尽可能在api层加载所需要的dll 使用时需要注意

  • 实体对象是否继承IShardingEntity
  • 实体对象是否有ShardingKey
  • 实体对象是否已经实现了一个虚拟路由
  • startup是否已经添加虚拟路由
代码语言:javascript
复制
 services.AddShardingSqlServer(o =>
  {
      o.ConnectionString = "";
      o.AddSharding<SysUserModVirtualRoute>();
      o.UseShardingCoreConfig((provider, config) =>
      {
          //如果是development就判断并且新建数据库如果不存在的话(ishardingentity不会被创建)
          config.EnsureCreated = provider.GetService<IHostEnvironment>().IsDevelopment();
          //ishardingentity表是否需要在启动时创建(如果已创建可以选择不创建)
          config.CreateShardingTableOnStart = true;
      });
  });
  • startup
代码语言:javascript
复制
  var shardingBootstrapper = app.ApplicationServices.GetRequiredService<IShardingBootstrapper>();
  shardingBootstrapper.Start();

计划

  • [提供官网如果该项目比较成功的话]
  • [开发更完善的文档]
  • [支持分库]
  • [支持更多数据库查询]

最后

理论上该库的思想可以解决大部分orm的分表,目前是仅针对efcore的后期如果可以获取也会对其他orm进行sharding库的开发 该框架借鉴了大部分分表组件的思路,目前提供的接口都已经实现,并且支持跨表查询,基于分页查询该框架也使用了流式查询保证不会再skip大数据的时候内存会爆炸,至于groupby目前已经在开发支持了,相信不久后就会发布新版本,目前这个库只是一个刚刚成型的库还有很多不完善的地方希望大家多多包涵,如果喜欢的话也希望大家给个star. 该文档是我晚上赶工赶出来的也想趁热打铁希望更多的人关注,也希望更多的人可以交流。

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ShardingCore
    • 依赖
    • 开始
      • 简介
        • 概念
          • 优点
            • 缺点
              • 安装
                • 配置
                  • 使用
                    • Api
                      • 默认路由
                      • 高级
                        • 批量操作
                          • 手动路由
                            • 自动建表
                              • 事务
                              • 注意事项
                              • 计划
                              • 最后
                              相关产品与服务
                              数据库
                              云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
                              领券
                              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档