.NET ORM 分表分库【到底】怎么做?

摘要:
安装NUGET安装只需要引用一个dll即可:SqlSugarCore5.0.4.3-preview06注意:需要升级5.0.4.3-preview06,nuget勾选允许预览版本一、分表使用场景(1).NET可扩展架构设计,比如一个ERP用5年不卡,到了10就卡了因为数据太多了,这个时候很多人都是备份然后清空数据(2).NET数据量太多,例如每天都有几十上百万的数据进入库,如果不分表后面查询将会非

安装NUGET安装

只需要引用一个dll 即可 :SqlSugarCore5.0.4.3-preview06

.NET ORM 分表分库【到底】怎么做?第1张

注意:需要升级5.0.4.3-preview06,nuget勾选允许预览版本

一、分表使用场景

(1).NET可扩展架构设计,比如一个ERP用5年不卡,到了10就卡了因为数据太多了,这个时候很多人都是备份然后清空数据

(2).NET数据量太多 ,例如每天都有几十上百万的数据进入库,如果不分表后面查询将会非常缓慢

(3) .NET性能瓶颈 ,数据库现有数据超过1个亿,很多情况下索引会莫名失效,性能大大下降

二、内置分表使用

.NET 自带分表支持按年、按季、按月、按周、按日进行分表

2.1定义实体

我们定义一个实体,主键不能用自增或者int ,设为long或者guid都可以,我例子就用自带的雪花ID实现分表

[SplitTable(SplitType.Year)]//按年分表 (自带分表支持 年、季、月、周、日)
[SugarTable("SplitTestTable_{year}{month}{day}")]//生成表名格式 3个变量必须要有
 public classSplitTestTable
 {
     [SugarColumn(IsPrimaryKey =true)]
     public long Id { get; set; }
 
     public string Name { get; set; }
     
     [SplitField] //分表字段 在插入的时候会根据这个字段插入哪个表,在更新删除的时候用这个字段找出相关表
     public DateTime CreateTime { get; set; }
 } 

2.2同步表和结构

假如分了20张表,实体类发生变更,那么 20张表可以自动同步结构,与实体一致

db.CodeFirst.SplitTables().InitTables<SplitTestTable>(); //程序启动时加这一行,如果一张表没有会初始化一张

2.3查询分表

(1)时间过滤

通过开始时间和结束时间自动生成CreateTime的过滤并且找到对应时间的表

var list=db.Queryable<OrderSpliteTest>().SplitTable(DateTime.Now.Date.AddYears(-1),DateTime.Now).ToPageList(1,2); 

(2)选择具体表

如果下面是按年分表 Take(3) 表示只查最近3年的分表数据

var list=db.Queryable<OrderSpliteTest>()
            .Where(it=>it.Pk==Guid.NewGuid())
            .SplitTable(tabs => tabs.Take(3))//近3张,也可以表达式选择
            .ToList();

(3)精准定位一张表

根据分表字段的值可以精准的定位到具体是哪一个分表,比Take(N)性能要高出很多

var name=Db.SplitHelper<SplitTestTable>().GetTableName(data.CreateTime);//根据时间获取表名
Db.Queryable<SplitTestTable>().Where(it => it.Id==data.Id).SplitTable(tas => tas.InTableNames(name)).ToList();

(4)表达式定位哪几张表

Db.Queryable<SplitTestTable>()
               .Where(it => it.Id==data.Id)
                .SplitTable(tas => tas.Where(y=>y.TableName.Contains("2019")))//表名包含2019的表
                .ToList();

(5)分表Join正常表

//分表使用联表查询
var list=db.Queryable<Order>() //Order是分表
.SplitTable(tabs=>tabs.Take(3)) 
.LeftJoin<Custom>((o,c)=>o.CustomId==c.Id)//Custom正常表
.Select((o,c)=>new { name=o.Name,cname=c.Name }).ToPageList(1,2); 

(6)分表JOIN分表

var rightQuery=db.Queryable<Custom>().SplitTable(tabs=>tabs.Take(3)) ;
var list=db.Queryable<Order>().SplitTable(tabs=>tabs.Take(3)) 
.LeftJoin<Custom>(rightQuery,(o,c)=>o.CustomId==c.Id) //Join  rightQuery
.Select((o,c)=>new { name=o.Name,cname=c.Name }).ToPageList(1,2); 

(7)性能优化

条件尽可能写在SplitTable前面,因为这样会先过滤在合并

2.3插入 

因为我们用的是Long所以采用雪花ID插入(guid也可以禁止使用自增列),实体结构看上面 3.1

注意:.SplitTable不要漏掉了

var data = newSplitTestTable()
{
      CreateTime=Convert.ToDateTime("2019-12-1"),
      Name="jack"};
 db.Insertable(data).SplitTable().ExecuteReturnSnowflakeId();//插入并返回雪花ID 
 
//sql 如下
//INSERT INTO [SplitTestTable_20190101] --如果表不存在会自动建表
//([Id],[Name],[CreateTime])
//VALUES
//(@Id,@Name,@CreateTime)

批量插入 因为我们是根据CreateTime进行的分表,生成的SQL语句如下:

var datas = new List<SplitTestTable>(){
new SplitTestTable(){CreateTime=Convert.ToDateTime("2019-12-1"),Name="jack"} ,
new SplitTestTable(){CreateTime=Convert.ToDateTime("2022-02-1"),Name="jack"},
new SplitTestTable(){CreateTime=Convert.ToDateTime("2020-02-1"),Name="jack"},
new SplitTestTable(){CreateTime=Convert.ToDateTime("2021-12-1"),Name="jack"}
};

db.Insertable(datas).SplitTable().ExecuteReturnSnowflakeIdList();//插入返回雪花ID集合

执行完生成的表

.NET ORM 分表分库【到底】怎么做?第2张

生成的Sql: 

.NET ORM 分表分库【到底】怎么做?第3张

自动识别4条记录,分别插入4个不同的表中  

2.4删除数据 

(1)最近3张表都执行一遍删除

db.Deleteable<SplitTestTable>().In(id).SplitTable(tas=>tas.Take(3)).ExecuteCommand();

(2)精准删除   

相对于上面的操作性能更高,可以精准找到具体表

var deldata = newSplitTestTable()
            {
                Id =id,
                CreateTime =DateTime.Now
            };
 var tableName =db.SplitHelper(deldata).GetTableNames();
 db.Deleteable<SplitTestTable>().Where(deldata).SplitTable(tas=>tas.InTableNames(tableName)).ExecuteCommand();
 //DELETE FROM [SplitTestTable_20210101] WHERE [Id] IN (1454676863531089920)

2.5更新数据   

更新的用法基本上和删除一样

//更新近3张表
db.Updateable(deldata).SplitTable(tas=>tas.Take(3)).ExecuteCommand();

//精准找到表名并且更新数据
var tableName =db.SplitHelper(deldata).GetTableNames();
db.Updateable(deldata).SplitTable(tas =>tas.InTableNames(tableName)).ExecuteCommand();

//通过表达式过滤出要更新的表
db.Updateable(deldata).SplitTable(tas => tas.Where(y=>y.TableName.Contains("_2019"))).ExecuteCommand();
 

三、 自定义分表

上面的分表功能是我们自带集成的,比如我想实现自定义的分表我该如何实现呢?

3.1 按首字母拼音分表

我们就写个按24个字母进行分表的小例子,来学习一下如何自定义分表

3.2 创建分表类

我们新建一个类继承成ISplitTableService接口

 public interfaceISplitTableService
 {
        //获取表名用于 SplitTable tas 筛选
        List<SplitTableInfo> GetAllTables(ISqlSugarClient db,EntityInfo EntityInfo,List<DbTableInfo>tableInfos);
        //获取默认表名
        stringGetTableName(ISqlSugarClient db, EntityInfo EntityInfo);
        stringGetTableName(ISqlSugarClient db, EntityInfo EntityInfo, SplitType type);
        //根据分表字段获取表名
        string GetTableName(ISqlSugarClient db, EntityInfo entityInfo, SplitType splitType, objectfieldValue);
        //获取分表字段的值
        object GetFieldValue(ISqlSugarClient db, EntityInfo entityInfo, SplitType splitType, objectentityValue);
 }

3.3 使用自定义分表

创建一个WordSplitService.cs继承ISplitTableService

用例下载:.NET ORM 分表分库【到底】怎么做?第4张USplit.zip

//配置自定义分表
db.CurrentConnectionConfig.ConfigureExternalServices.SplitTableService =newWordSplitService();

//插入数据
db.Insertable(new WordTestTable(){CreateTime=DateTime.Now,Name="BC"}).SplitTable().ExecuteReturnSnowflakeId();
db.Insertable(new WordTestTable(){CreateTime=DateTime.Now,Name="AC"}).SplitTable().ExecuteReturnSnowflakeId();
db.Insertable(new WordTestTable(){CreateTime=DateTime.Now,Name="ZBZ"}).SplitTable().ExecuteReturnSnowflakeId();  

.NET ORM 分表分库【到底】怎么做?第5张

执行完数据库就多了3张表,因为是按首字母分的表 ,插入了3条记录自动创建了3张表,插入生成的SQL:

INSERT INTO [WordTestTable_FirstB]
           ([Id],[Name],[CreateTime])
     VALUES
           (@Id,@Name,@CreateTime) ;
INSERT INTO [WordTestTable_FirstA]
           ([Id],[Name],[CreateTime])
     VALUES
           (@Id,@Name,@CreateTime) ;
INSERT INTO [WordTestTable_FirstZ]
           ([Id],[Name],[CreateTime])
     VALUES
           (@Id,@Name,@CreateTime) ;

查询分表

//查询字母A开头的分
var listall = db.Queryable<WordTestTable>().Where(it => it.Name == "all").SplitTable(tas => tas.ContainsTableNames("_FirstA")).ToList();    
//生成的SQL:
//SELECT * FROM  (SELECT [Id],[Name],[CreateTime] FROM [WordTestTable_FirstA]  WHERE ( [Name] = @Name0UnionAll1 )) unionTable 

原码地址:https://github.com/donet5/SqlSugar

.NET 生态还处于较弱的状态,呼吁大家支持、踊跃参与开源项目,为下一个 .NET 开源社区五年计划做贡献。

希望正在使用的、善良的您能动一动小手指,把文章转发一下,让更多人知道 .NET 有这样一个好用的 ORM 存在。谢谢了!!

免责声明:文章转载自《.NET ORM 分表分库【到底】怎么做?》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇NGUI的anchors属性的使用如何在Ubuntu server中修改IP下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Java—SSH(MVC)

Java—SSH(MVC) 1. 谈谈你mvc的理解 MVC是Model—View—Controler的简称。即模型—视图—控制器。MVC是一种设计模式,它强制性的把应用程序 的输入、处理和输出分开。 MVC中的模型、视图、控制器它们分别担负着不同的任务。 视图: 视图是用户看到并与之交互的界面。视图向用户显示相关的数据,并接受用户的输入。视图不进行任何...

Spring Boot (三): ORM 框架 JPA 与连接池 Hikari

前面两篇文章我们介绍了如何快速创建一个 Spring Boot 工程《Spring Boot(一):快速开始》和在 Spring Boot 中如何使用模版引擎 Thymeleaf 渲染一个Web页面《Spring Boot (二):模版引擎 Thymeleaf 渲染 Web 页面》,本篇文章我们继续介绍在 Spring Boot 中如何使用数据库。 1....

python ORM框架:SqlAlchemy

  ORM,对象关系映射,即Object Relational Mapping的简称,通过ORM框架将编程语言中的对象模型与数据库的关系模型建立映射关系,这样做的目的:简化sql语言操作数据库的繁琐过程(原生sql的编写及拼接等),转而直接使用对象模型来操作数据库做替代 第一部分       SqlAlchemy本身无法直接操作数据库,它是建立在第三...

持久层框架:MyBatis 3.2(1)

MyBatis 的前身就是 iBatis 。是一个数据持久层(ORM)框架。 iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAO),同时还提供一个利用这个框架开发的 JPetStore实例。  看到Mybati...

hibernate的配置文件(ORM元数据配置、主配置文件)

一、orm元数据配置: 位置在实体类的包中:  一个关于学生表和学生实体的一对一映射文件的配置: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3....

六、Django的orm之单表操作

Django模型层(一)单表操作 一、ORM ORM是“对象-关系-映射”的简称。(Object Relational Mapping,简称ORM) orm其实就是将类对象的语法翻译成sql语句的一个引擎 类对象 --- sql 类 -- 表 对象 -- 行 属性 -- 字段 原生sql和Python的orm代码对比: 二、Django连接数据库 在Dj...