当业务系统的数据量突破千万甚至亿级级别时,单表的查询和写入性能会明显下降,索引维护成本也会大幅增加,此时分表分库是常用的优化方案。分表是将一张大表按照规则拆分成多张结构相同的子表,分库是将拆分后的表分布到不同的数据库实例中,以此降低单节点的存储和访问压力。

ShardingCore框架简介
ShardingCore是一款针对C#生态的开源分表分库框架,它基于EF Core实现,支持按照时间、哈希、范围等多种规则进行分表分库,同时兼容大部分EF Core的原有用法,开发者不需要大幅修改现有代码就能接入分表分库能力,降低了迁移成本。
环境准备与依赖安装
首先需要在C#项目中安装ShardingCore相关的NuGet包,这里以.NET 6项目为例,需要安装以下两个核心包:
- ShardingCore
- ShardingCore.Core
如果使用SQL Server数据库,还需要安装对应的EF Core数据库驱动:
- Microsoft.EntityFrameworkCore.SqlServer
定义分片规则
分片规则是分表分库的核心,我们需要先定义实体类,再配置对应的分片逻辑。假设我们有一个订单表,按照订单创建时间按月分表。
1. 定义订单实体类
首先创建订单实体,包含订单的基本字段:
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace ShardingDemo.Entities
{
[Table("Order")]
public class Order
{
[Key]
public string Id { get; set; }
public string OrderNo { get; set; }
public decimal Amount { get; set; }
public DateTime CreateTime { get; set; }
}
}
2. 配置分表规则
接下来创建分表规则配置类,指定按照CreateTime字段按月分表:
using ShardingCore.Core.EntityMetadatas;
using ShardingCore.Core.ShardingConfigurations.Abstractions;
using ShardingCore.Core.VirtualRoutes;
using ShardingCore.Core.VirtualRoutes.TableRoutes.Abstractions;
using ShardingCore.Helpers;
using ShardingDemo.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
namespace ShardingDemo.ShardingConfig
{
public class OrderVirtualTableRoute : AbstractShardingTimeKeyDateTimeVirtualTableRoute<Order>
{
// 指定分表的时间字段
public override string ShardingKeyToTail(DateTime time)
{
return time.ToString("yyyyMM");
}
// 获取分片键的值
public override Func<string, bool> GetRouteToFilter(DateTime shardingKey, ShardingOperatorEnum shardingOperator)
{
return base.GetRouteToFilter(shardingKey, shardingOperator);
}
// 配置分表的后缀格式,这里按月分表,后缀为yyyyMM
protected override string TimeFormatToTail(DateTime time)
{
return time.ToString("yyyyMM");
}
// 获取所有分表的后缀,这里示例返回最近3个月的分表后缀
public override List<string> GetAllTails()
{
var result = new List<string>();
var now = DateTime.Now;
for (int i = 0; i < 3; i++)
{
result.Add(now.AddMonths(-i).ToString("yyyyMM"));
}
return result;
}
}
}
配置DbContext与ShardingCore
接下来需要配置EF Core的DbContext,同时集成ShardingCore的分片能力。
1. 创建分片DbContext
using Microsoft.EntityFrameworkCore;
using ShardingCore.Core.DbContextInfos;
using ShardingCore.Extensions;
using ShardingDemo.Entities;
using System;
using System.Linq;
namespace ShardingDemo.Data
{
public class ShardingDbContext : DbContext
{
public DbSet<Order> Orders { get; set; }
public ShardingDbContext(DbContextOptions<ShardingDbContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Order>(entity =>
{
entity.HasKey(e => e.Id);
entity.Property(e => e.OrderNo).HasMaxLength(50);
});
}
// 重写SaveChanges方法,支持分片写入
public override int SaveChanges()
{
return this.SaveChangesSharding();
}
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
return this.SaveChangesShardingAsync(cancellationToken);
}
}
}
2. 注册ShardingCore服务
在Program.cs中注册ShardingCore相关服务,配置数据库连接和分片规则:
using Microsoft.EntityFrameworkCore;
using ShardingCore.Core.ShardingConfigurations;
using ShardingCore.Extensions;
using ShardingDemo.Data;
using ShardingDemo.ShardingConfig;
var builder = WebApplication.CreateBuilder(args);
// 注册ShardingCore服务
builder.Services.AddShardingDbContext<ShardingDbContext>(
(conStr, builder) =>
{
builder.UseSqlServer(conStr);
},
opt =>
{
opt.UseShardingOptions(new ShardingOptions()
.AddShardingTableRoute<OrderVirtualTableRoute>());
},
builder.Configuration.GetConnectionString("DefaultConnection")
);
var app = builder.Build();
// 初始化ShardingCore,确保分表路由生效
app.Services.UseShardingCore();
app.MapGet("/", () => "ShardingCore Demo Running");
app.Run();
这里需要在appsettings.json中配置数据库连接字符串,示例配置如下:
{
"ConnectionStrings": {
"DefaultConnection": "Server=127.0.0.1;Database=ShardingDemo;User Id=sa;Password=your_password;"
}
}
分表数据操作示例
配置完成后,就可以像使用普通EF Core一样操作分表数据,ShardingCore会自动根据分片规则路由到对应的表。
1. 插入分表数据
using Microsoft.AspNetCore.Mvc;
using ShardingDemo.Data;
using ShardingDemo.Entities;
using System;
using System.Threading.Tasks;
namespace ShardingDemo.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class OrderController : ControllerBase
{
private readonly ShardingDbContext _dbContext;
public OrderController(ShardingDbContext dbContext)
{
_dbContext = dbContext;
}
[HttpPost("add")]
public async Task<IActionResult> AddOrder()
{
var order = new Order
{
Id = Guid.NewGuid().ToString(),
OrderNo = "ORD" + DateTime.Now.ToString("yyyyMMddHHmmss"),
Amount = 100.5m,
CreateTime = DateTime.Now
};
_dbContext.Orders.Add(order);
await _dbContext.SaveChangesAsync();
return Ok("订单添加成功");
}
}
}
插入数据时,ShardingCore会根据CreateTime的值自动计算分表后缀,将数据写入对应的月份订单表中,如果对应的分表不存在,框架会自动创建。
2. 查询分表数据
查询时如果带了分片键条件,ShardingCore会自动路由到对应的分表,提升查询效率:
[HttpGet("list")]
public async Task<IActionResult> GetOrderList()
{
// 查询当月创建的订单,会自动路由到对应月份的分表
var orders = await _dbContext.Orders
.Where(o => o.CreateTime >= DateTime.Now.Date && o.CreateTime < DateTime.Now.AddDays(1))
.ToListAsync();
return Ok(orders);
}
如果没有带分片键条件,ShardingCore会查询所有分表的数据并合并结果,不过这种全表扫描的性能会低于带分片条件的查询,实际使用中尽量带上分片键条件。
分库配置说明
如果需要分库,只需要在ShardingCore的配置中添加多数据库配置即可,比如按照订单Id的哈希值分配到不同的数据库实例:
// 分库路由配置示例,按照订单Id哈希分库
public class OrderVirtualDataSourceRoute : AbstractShardingKeyStringVirtualDataSourceRoute<Order>
{
private readonly List<string> _dataSourceNames = new List<string> { "db0", "db1", "db2" };
public override string ShardingKeyToDataSourceName(string shardingKey)
{
// 简单哈希取模分配数据库
var hash = Math.Abs(shardingKey.GetHashCode()) % _dataSourceNames.Count;
return _dataSourceNames[hash];
}
public override List<string> GetAllDataSourceNames()
{
return _dataSourceNames;
}
public override Func<string, bool> GetRouteToFilter(string shardingKey, ShardingOperatorEnum shardingOperator)
{
return base.GetRouteToFilter(shardingKey, shardingOperator);
}
}
然后在服务注册时同时添加分表路由和分库路由即可实现分表分库组合使用。
注意事项
- 分片键的选择非常重要,尽量选择查询频率高、区分度高的字段作为分片键,避免后续查询出现全分片扫描的情况。
- 分表后如果需要跨分表做聚合查询,性能会比单表差,尽量在业务层面避免复杂的跨分片聚合操作。
- ShardingCore支持分表的自动创建和迁移,但是生产环境建议提前做好分表的规划,避免频繁创建分表带来的性能波动。
- 如果使用的是其他数据库比如MySQL、PostgreSQL,只需要替换对应的EF Core数据库驱动,配置方式基本一致。
C#ShardingCore分表分库超大数据量存储修改时间:2026-07-10 01:48:41