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


安裝NUGET安裝

只需要引用一個dll 即可 : SqlSugarCore 5.0.4.3-preview06

注意:需要升級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 class SplitTestTable
 {
     [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 = new SplitTestTable()
{
      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集合

 執行完生成的表

生成的Sql: 

自動識別4條記錄,分別插入4個不同的表中  

2.4 刪除數據 

(1)最近3張表都執行一遍刪除

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

(2)精准刪除     

 相對於上面的操作性能更高,可以精准找到具體表

var deldata = new SplitTestTable()
            {
                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 interface ISplitTableService
 {
        //獲取表名用於 SplitTable tas 篩選
        List<SplitTableInfo> GetAllTables(ISqlSugarClient db,EntityInfo EntityInfo,List<DbTableInfo> tableInfos);
        //獲取默認表名
        string GetTableName(ISqlSugarClient db, EntityInfo EntityInfo);
        string GetTableName(ISqlSugarClient db, EntityInfo EntityInfo, SplitType type);
        //根據分表字段獲取表名
        string GetTableName(ISqlSugarClient db, EntityInfo entityInfo, SplitType splitType, object fieldValue);
        //獲取分表字段的值
        object GetFieldValue(ISqlSugarClient db, EntityInfo entityInfo, SplitType splitType, object entityValue);
 }

3.3  使用自定義分表

創建一個WordSplitService.cs繼承ISplitTableService

用例下載: USplit.zip

//配置自定義分表
db.CurrentConnectionConfig.ConfigureExternalServices.SplitTableService =new WordSplitService();

//插入數據
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();  

 執行完數據庫就多了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 存在。謝謝了!!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM