sharding-core

csd
csd
2小时前发布 /正在检测是否收录...
广告 广告 广告 广告 广告 广告 广告 广告 广告 广告

项目介绍

high performance lightweight solution for efcore sharding table and sharding database support read-write-separation .一款ef-core下高性能、轻量级针对分表分库读写分离的解决方案,具有零依赖、零学习成本、零业务代码入侵

项目详情

项目截图

项目截图

English | 中文

ShardingCore

一款ef-core下高性能、轻量级针对分表分库读写分离的解决方案。

  • 零依赖
  • 零学习成本
  • 零业务代码入侵

特别用户

项目截图

全项目基于.Net专业团队自研,源头工厂,价格约是官方的二十分之一不到,获得全网数万用户好评,稳定安全,快速可靠!

  • ①支持 编程/对话/视频/图片/翻译/知识库/插件 直接使用 等等。
  • ②支持全球顶流模型,支持最强编程ClaudeCode/Codex/GeminiCli。
  • ③支持一个key通用claude、gpt、gemini等全站模型。
  • ④包售后,充值后提供1对1售后服务,手把手教玩ai 。

用Ai就选择意心Ai,省心放心爽用!让你不再有Ai焦虑!

项目截图

项目截图

社区合作伙伴和赞助商

项目截图

📚 Documentation

中文文档

如何选择版本

  • shardingcore 最新版本.efcore版本.x.x
  • 版本号第一位是shardingcore的版本号使用最大的即可
  • 版本号第二位是efcore版本号使用对应的版本号即可
  • 最后两位版本号使用最大即可
  • efcore10使用shardingcore7.10.x.x,
  • efcore9使用shardingcore7.9.x.x,
  • efcore8使用shardingcore7.8.x.x,
  • efcore7使用shardingcore7.7.x.x,
  • efcore6使用shardingcore7.6.x.x,
  • efcore5使用shardingcore7.5.x.x,
  • efcore3使用shardingcore7.3.x.x,
  • efcore2使用shardingcore7.2.x.x

Abp.VNext、WTM、FURION 框架集成

依赖

ShardingCore 6.7.0.0之前版本

版本号:a.b.c.d其中,a表示efcore版本号

ReleaseEF Core.NET.NET (Core)
6.x.x.x6.0.0net 6.06.0+
5.x.x.x5.0.10Standard 2.15.0+
3.x.x.x3.1.18Standard 2.02.0+
2.x.x.x2.2.6Standard 2.02.0+

ShardingCore 6.7.0.0之后

版本号:a.b.c.d其中已无相关efcore选择,使用条件编译绑定.net平台,6.7.0.0之后如果您是netcoreapp2那么直接使用efcore2,如果是netcoreapp3那么直接使用efcore3如果是net5就直接用efcore6依次类推

ReleaseEF Core.NET (Core)
6.7.0.0+6.xnet6
6.7.0.0+5.xnet5 or netstandard2.1
6.7.0.0+3.xnetcoreapp3 or netstandard2.0
6.7.0.0+2.xnetcoreapp2

快速开始

5步实现按月分表,且支持自动化建表建库

第一步安装依赖

选择您的efcore的数据库驱动版本

# 请对应安装您需要的版本
PM> Install-Package ShardingCore
# use sqlserver
PM> Install-Package Microsoft.EntityFrameworkCore.SqlServer
#  use mysql
#PM> Install-Package Pomelo.EntityFrameworkCore.MySql
# use other database driver,if efcore support

第二步创建查询对象

查询对象


/// 
/// order table
/// 
public class Order
{
/// 
/// order Id
/// 
public string Id { get; set; }
/// 
/// payer id
/// 
public string Payer { get; set; }
/// 
/// pay money cent
/// 
public long Money { get; set; }
/// 
/// area
/// 
public string Area { get; set; }
/// 
/// order status
/// 
public OrderStatusEnum OrderStatus { get; set; }
/// 
/// CreationTime
/// 
public DateTime CreationTime { get; set; }
}
public enum OrderStatusEnum
{
NoPay=1,
Paying=2,
Payed=3,
PayFail=4
}

第三步创建dbcontext

dbcontext AbstractShardingDbContext和IShardingTableDbContext如果你是普通的DbContext那么就继承AbstractShardingDbContext需要分表就实现IShardingTableDbContext,如果只有分库可以不实现IShardingTableDbContext接口


public class MyDbContext:AbstractShardingDbContext,IShardingTableDbContext
{
public MyDbContext(DbContextOptions options) : base(options)
{
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity(entity =>
{
entity.HasKey(o => o.Id);
entity.Property(o => o.Id).IsRequired().IsUnicode(false).HasMaxLength(50);
entity.Property(o=>o.Payer).IsRequired().IsUnicode(false).HasMaxLength(50);
entity.Property(o => o.Area).IsRequired().IsUnicode(false).HasMaxLength(50);
entity.Property(o => o.OrderStatus).HasConversion();
entity.ToTable(nameof(Order));
});
}
/// 
/// empty impl if use sharding table
/// 
public IRouteTail RouteTail { get; set; }
}

第四步添加分表路由

路由构造函数支持依赖注入,依赖注入的对象生命周期必须是单例
public class OrderVirtualTableRoute:AbstractSimpleShardingMonthKeyDateTimeVirtualTableRoute
{
/// 
/// fixed value don't use DateTime.Now because if  if application restart this value where change
/// 
/// 
public override DateTime GetBeginTime()
{
return new DateTime(2021, 1, 1);
}
/// 
/// configure sharding property
/// 
/// 

public override void Configure(EntityMetadataTableBuilder builder)
{
builder.ShardingProperty(o => o.CreationTime);
}
/// 
/// enable auto create table job
/// 
/// 

public override bool AutoCreateTableByTime()
{
return true;
}
}

第五步配置启动项

无论你是何种数据库只需要修改AddDefaultDataSource里面的链接字符串 请不要修改委托内部的UseXXX参数 conStr and connection


public void ConfigureServices(IServiceCollection services)
{

//额外添加分片配置
services.AddShardingDbContext()
.UseRouteConfig(op =>
{
op.AddShardingTableRoute();
}).UseConfig(op =>
{
op.UseShardingQuery((connStr, builder) =>
{
//connStr is delegate input param
builder.UseSqlServer(connStr);
});
op.UseShardingTransaction((connection, builder) =>
{
//connection is delegate input param
builder.UseSqlServer(connection);
});
//use your data base connection string
op.AddDefaultDataSource(Guid.NewGuid().ToString("n"),
"Data Source=localhost;Initial Catalog=EFCoreShardingTableDB;Integrated Security=True;");
}).AddShardingCore();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
//not required, enable check table missing and auto create,非必须  启动检查缺少的表并且创建
app.ApplicationServices.UseAutoTryCompensateTable();
// other configure....
}

这样所有的配置就完成了你可以愉快地对Order表进行按月分表了

[Route("api/[controller]")]
public class ValuesController : Controller
{
private readonly MyDbContext _myDbContext;

public ValuesController(MyDbContext myDbContext)
{
_myDbContext = myDbContext;
}

[HttpGet]
public async Task Get()
{
var order = await _myDbContext.Set().FirstOrDefaultAsync(o => o.Id == "2");
return OK(order)
}
}

性能

Test

  • on expression compile cache
  • ShardingCore x.3.1.63+ version
  • efcore 6.0 version
  • order id is string, sharding mod(hashcode%5)
  • N mean execute count

Benchmark Demo

性能损耗 sql server 2012,data rows 7734363 =773w

// Summary

BenchmarkDotNet=v0.13.1, OS=Windows 10.0.18363.1500 (1909/November2019Update/19H2)
AMD Ryzen 9 3900X, 1 CPU, 24 logical and 12 physical cores
.NET SDK=6.0.100
[Host] : .NET 6.0.0 (6.0.21.52210), X64 RyuJIT
DefaultJob : .NET 6.0.0 (6.0.21.52210), X64 RyuJIT

MethodNMeanErrorStdDev
NoShardingIndexFirstOrDefaultAsync101.512 ms0.0071 ms0.0063 ms
ShardingIndexFirstOrDefaultAsync101.567 ms0.0127 ms0.0113 ms

针对未分片数据的查询性能,可以看出10次查询差距为0.05ms,单次查询损耗约为5微妙=0.005毫秒,损耗占比为3%,

结论:efcore 原生查询和sharding-core的查询在针对未分片对象查询上性能可达原先的97%具有极高的性能

性能测试

sql server 2012,data rows 7734363 =773w

// Summary

BenchmarkDotNet=v0.13.1, OS=Windows 10.0.18363.1500 (1909/November2019Update/19H2)
AMD Ryzen 9 3900X, 1 CPU, 24 logical and 12 physical cores
.NET SDK=6.0.101
[Host] : .NET 6.0.1 (6.0.121.56705), X64 RyuJIT
DefaultJob : .NET 6.0.1 (6.0.121.56705), X64 RyuJIT

MethodNMeanErrorStdDev
NoShardingIndexFirstOrDefaultAsync101.678 ms0.0323 ms0.0359 ms
ShardingIndexFirstOrDefaultAsync102.005 ms0.0161 ms0.0143 ms
NoShardingNoIndexFirstOrDefaultAsync10495.933 ms9.4911 ms10.5494 ms
ShardingNoIndexFirstOrDefaultAsync10596.112 ms11.8907 ms13.2165 ms
NoShardingNoIndexCountAsync10477.537 ms1.4817 ms1.2373 ms
ShardingNoIndexCountAsync10594.833 ms7.4057 ms5.7819 ms
NoShardingNoIndexLikeToListAsync10665.277 ms1.3382 ms1.1174 ms
ShardingNoIndexLikeToListAsync10840.865 ms16.1917 ms17.3249 ms
NoShardingNoIndexToListAsync10480.368 ms1.3688 ms1.2134 ms
ShardingNoIndexToListAsync10604.850 ms8.6204 ms8.0635 ms

mysql 5.7,data rows 7553790=755w innerdb_buffer_size=3G

// Summary

BenchmarkDotNet=v0.13.1, OS=Windows 10.0.18363.1500 (1909/November2019Update/19H2)
AMD Ryzen 9 3900X, 1 CPU, 24 logical and 12 physical cores
.NET SDK=6.0.101
[Host] : .NET 6.0.1 (6.0.121.56705), X64 RyuJIT
DefaultJob : .NET 6.0.1 (6.0.121.56705), X64 RyuJIT

MethodNMeanErrorStdDev
NoShardingIndexFirstOrDefaultAsync105.646 ms0.0164 ms0.0145 ms
ShardingIndexFirstOrDefaultAsync105.679 ms0.0359 ms0.0319 ms
NoShardingNoIndexFirstOrDefaultAsync105,212.736 ms230.0841 ms678.4080 ms
ShardingNoIndexFirstOrDefaultAsync102,013.107 ms10.4256 ms9.2420 ms
NoShardingNoIndexCountAsync109,483.988 ms42.0931 ms39.3739 ms
ShardingNoIndexCountAsync102,029.698 ms12.4008 ms10.9929 ms
NoShardingNoIndexLikeToListAsync1010,569.283 ms20.9163 ms16.3301 ms
ShardingNoIndexLikeToListAsync102,208.804 ms11.0483 ms10.3346 ms
NoShardingNoIndexToListAsync109,485.263 ms21.2558 ms17.7496 ms
ShardingNoIndexToListAsync102,012.086 ms39.2986 ms45.2563 ms

具体可以通过first前两次结果来计算得出结论单次查询的的损耗为0.04毫秒上下, sqlserver的各项数据在分表和未分表的情况下都几乎差不多可以得出在770w数据集情况下数据库还并未是数据瓶颈的关键,但是mysql可以看到在分表和未分表的情况下如果涉及到没有索引的全表扫描那么性能的差距将是分表后的表数目之多,测试中为5-6倍,也就是分表数目

使用介绍

以下所有例子都以Sql Server为例 展示的代码均是分表为例,如果需要分库可以参考Sample.SqlServerShardingDataSource 其他数据库亦是如此

简介

简单介绍下这个库,这个库的所有版本都是由对应的efcore版本号为主的版本,第二个版本号如果是2的表示仅支持分库,如果是3+的表示支持分库分表,这个库目前分成两个主要版本一个是main分支一个是shardingTableOnly分支,该库支持分库完全自定义路由适用于95%的业务需求,分表支持x+y+z,x表示固定的表名,y表示固定的表名和表后缀之间的联系(可以为空),z表示表后缀,可以按照你自己的任意业务逻辑进行切分,
如:user_0,user_1或者user202101,user202102...当然该库同样适用于多租户模式下的隔离
支持多种查询包括join,group by,max,count,min,avg,sum ...等一系列查询,之后可能会添加更多支持,目前该库的使用非常简单,基本上就是针对IQueryable的扩展,为了保证
该库的干净零依赖,如果需要实现自动建表需要自己配合定时任务,即可完成24小时无人看管自动管理。该库提供了 IShardingTableCreator
作为建表的依赖,如果需要可以参考 按天自动建表 该demo是针对分库的动态添加

概念

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

分库概念

  • [DataSourceName]
    数据源名称用来将对象路由到具体的数据源
  • [IVirtualDataSource]
    虚拟数据源 IVirtualDataSource
  • [IVirtualDataSourceRoute]
    分库路由 IVirtualDataSourceRoute

    分表概念

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

优点

  • [支持自定义分库]
  • [支持读写分离]
  • [支持高性能分页]
  • [支持手动路由]
  • [支持批量操作]
  • [支持自定义分表规则]
  • [支持任意类型分表key]
  • [对dbcontext学习成本0]
  • [支持分表下的连表] join,group by,max,count,min,avg,sum
  • [支持针对批处理的使用] EFCore.BulkExtensions ...支持efcore的扩展生态
  • [提供多种默认分表规则路由] 按时间,按取模 可自定义
  • [针对分页进行优化] 大页数跳转支持低内存流式处理,高性能分页

缺点

  • [消耗连接]出现分表与分表对象进行join如果条件没法索引到具体表会生成笛卡尔积导致连接数爆炸,后期会进行针对该情况的配置

安装


or

or

开始

分表

我们以用户取模来做例子,配置entity 推荐 fluent api

public class SysUserMod 
{
/// 
/// 用户Id用于分表
/// 
public string Id { get; set; }
/// 
/// 用户名称
/// 
public string Name { get; set; }
/// 
/// 用户姓名
/// 
public int Age { get; set; }
}

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


public class SysUserModVirtualTableRoute : AbstractSimpleShardingModKeyStringVirtualRoute
{
//2 tail length:00,01,02......99
//3 hashcode % 3: [0,1,2]
public SysUserModVirtualTableRoute() : base(2,3)
{
}
public override void Configure(EntityMetadataTableBuilder builder)
{
builder.ShardingProperty(o => o.Id);
}
}

如果你使用分表必须创建一个继承自IShardingTableDbContext接口的DbContext,
必须实现IShardingDbContext,默认提供了AbstractShardingDbContext


  //DefaultTableDbContext is acutal execute dbcontext
public class DefaultShardingDbContext:AbstractShardingDbContext,IShardingTableDbContext
{
public DefaultShardingDbContext(DbContextOptions options) : base(options)
{
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfiguration(new SysUserModMap());
}
public IRouteTail RouteTail { get; set; }

}

Startup.cs 下的 ConfigureServices(IServiceCollection services)


public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
//if u want use no sharding operate
//services.AddDbContext(o => o.UseSqlServer("Data Source=localhost;Initial Catalog=ShardingCoreDB;Integrated Security=True"));

//add shardingdbcontext support life scope

services.AddShardingDbContext(
(conStr, builder) => builder.UseSqlServer(conStr)
)
.Begin(o =>
{
o.CreateShardingTableO

...(内容过长,已截断,更多详情请访问项目地址)

## ⬇️ 下载地址 ##

{cloud title="sharding-core 源码下载" type="gitee" url="https://gitee.com/xuejm/sharding-core/repository/archive/main.zip" /}

喜欢就支持一下吧
点赞 0 分享 赞赏
评论 抢沙发
OωO
取消
广告