<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          .NET 分庫(kù)分表高性能:瀑布流分頁(yè)

          共 5969字,需瀏覽 12分鐘

           ·

          2022-03-16 10:11


          ?框架介紹


          依照慣例首先介紹本期主角:ShardingCore 一款ef-core下高性能、輕量級(jí)針對(duì)分表分庫(kù)讀寫分離的解決方案,具有零依賴、零學(xué)習(xí)成本、零業(yè)務(wù)代碼入侵


          dotnet下唯一一款全自動(dòng)分表,多字段分表框架,擁有高性能,零依賴、零學(xué)習(xí)成本、零業(yè)務(wù)代碼入侵,并且支持讀寫分離動(dòng)態(tài)分表分庫(kù),同一種路由可以完全自定義的新星組件框架。


          項(xiàng)目地址

          github:https://github.com/dotnetcore/sharding-core

          gitee:https://gitee.com/dotnetchina/sharding-core


          背景


          在大數(shù)據(jù)量下針對(duì)app端的瀑布流頁(yè)面分頁(yè)的優(yōu)化實(shí)戰(zhàn),有大量的數(shù)據(jù),前端需要以瀑布流的形式展示出來,我們最簡(jiǎn)單的就是以用戶發(fā)布的文章為例,假設(shè)我們有大量的文章帖子被,需求需要按帖子的發(fā)布時(shí)間倒序展示給用戶看,那么在手機(jī)端我們一般都是以下拉刷新,上拉加載的形式去展示,那么我們一般會(huì)有以下集中寫法。


          常規(guī)分頁(yè)操作

          select?count(*)?from?article
          select?*?from?article?order?by?publish_time?desc?limit?0,20

          這個(gè)操作是一般我們的常規(guī)分頁(yè)操作,先進(jìn)行total然后進(jìn)行分頁(yè)獲取,這種做法的好處是支持任意規(guī)則的分頁(yè),缺點(diǎn)就是需要查詢兩次,一次count一次limit當(dāng)然后期數(shù)據(jù)量實(shí)在太大可以只需要第一次count,但是也有一個(gè)問題就是如果數(shù)據(jù)量一直在變化會(huì)出現(xiàn)下一次分頁(yè)中還會(huì)有上一次的部分?jǐn)?shù)據(jù),因?yàn)閿?shù)據(jù)在不斷地新增,你的分頁(yè)沒跟上發(fā)布的速度那么就會(huì)有這個(gè)情況發(fā)送.

          瀑布流分頁(yè)

          除了上述常規(guī)分頁(yè)操作外,我們針對(duì)特定順序的分頁(yè)也可以進(jìn)行特定的分頁(yè)方式來實(shí)現(xiàn)高性能,因?yàn)榛诖笄疤嵛覀兪谴髷?shù)量下的瀑布流,我們的文章假設(shè)是以雪花id作為主鍵,那么我們的分頁(yè)可以這么寫

          select?*?from?article?where?idorder?by?publish_time?desc?limit?0,20

          首先我們來分析一下,這個(gè)語(yǔ)句是利用了插入的數(shù)據(jù)分布是順序和你需要查詢的排序一直來實(shí)現(xiàn)的,又因?yàn)閕d不會(huì)重復(fù)并且雪花id的順序和時(shí)間是一致的都是同向的所以可以利用這種方式來進(jìn)行排序,limit每次不需要跳過任何數(shù)目,直接獲取需要的數(shù)目即可,只需要傳遞上一次的查詢結(jié)果的id即可,這個(gè)方式彌補(bǔ)了上述常規(guī)分頁(yè)帶來的問題,并且擁有非常高的性能,但是缺點(diǎn)也顯而易見,不支持跳頁(yè),不支持任意排序,所以這個(gè)方式目前來說非常適合前端app的瀑布流排序。

          分片下的實(shí)現(xiàn)

          首先分片下需要實(shí)現(xiàn)這個(gè)功能我們需要有id支持分片,并且publish_time按時(shí)間分表,兩者缺一不可。

          原理

          假設(shè)文章表article我們是以publish_time作為分片字段,假設(shè)按天分表,那么我們會(huì)擁有如下的表

          article_20220101、article_20220102、article_20220103、article_20220104、article_20220105、article_20220106......

          雪花id輔助分片

          因?yàn)?code style="font-size: 14px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">雪花id可以反解析出時(shí)間,所以我們對(duì)雪花id的=,>=,>,<=,<,contains的操作都是可以進(jìn)行輔助分片進(jìn)行縮小分片范圍 假設(shè)我們的雪花id解析出來是2021-01-05 11:11:11,那么針對(duì)這個(gè)雪花id<小于操作我們可以等價(jià)于x < 2021-01-05 11:11:11,那么如果我問你這下我們需要查詢的表有哪些,很明顯 [article_20220101、article_20220102、article_20220103、article_20220104、article_20220105],除了20220106外我們都需要查詢。

          union all分片模式

          如果你使用union all的分片模式那么通常會(huì)將20220101-20220105的所有的表進(jìn)行union all然后機(jī)械能過濾,那么優(yōu)點(diǎn)可想而知:簡(jiǎn)單,連接數(shù)消耗僅1個(gè),sql語(yǔ)句支持的多,缺點(diǎn)也顯而易見,優(yōu)化起來后期是個(gè)很大的問題,并且跨庫(kù)下的使用有問題

          select?*?from?
          (select?*?from?article_20220101?union?all?select?*?from?article_20220102?union?all?select?*?from?article_20220103....)?t
          ?where?idorder?by?publish_time?desc?limit?0,20

          流式分片,順序查詢

          如果你是流式分片模式進(jìn)行聚合通常我們會(huì)將20220101-20220105的所有的表進(jìn)行并行的分別查詢,然后針對(duì)每個(gè)查詢的結(jié)果集進(jìn)行優(yōu)先級(jí)隊(duì)列的排序后獲取,優(yōu)點(diǎn):語(yǔ)句簡(jiǎn)單便于優(yōu)化,性能可控,支持分庫(kù),缺點(diǎn):實(shí)現(xiàn)復(fù)雜,連接數(shù)消耗多

          select?*?from?article_20220101?where?idorder?by?publish_time?desc?limit?0,20
          select?*?from?article_20220102where?idorder?by?publish_time?desc?limit?0,20
          select?*?from?article_20220103?where?idorder?by?publish_time?desc?limit?0,20
          ......

          流式分片下的優(yōu)化

          目前 ShardingCore采用的是流式聚合+union all,當(dāng)且僅當(dāng)用戶手動(dòng)3調(diào)用UseUnionAllMerge時(shí)會(huì)將分片sql轉(zhuǎn)成union all 聚合。

          針對(duì)上述瀑布流的分頁(yè)ShardingCore是這么操作的

          • 確定分片表的順序,也就是因?yàn)榉制侄问?code style="font-size: 14px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">publish_time,又因?yàn)榕判蜃侄问?code style="font-size: 14px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">publish_time所以分片表其實(shí)是有順序的,也就是[article_20220105、article_20220104、article_20220103、article_20220102、article_20220101], 因?yàn)槲覀兪情_啟n個(gè)并發(fā)線程所以這個(gè)排序可能沒有意義,但是如果我們是僅開啟設(shè)置單個(gè)連接并發(fā)的時(shí)候,程序?qū)F(xiàn)在通過id進(jìn)行表篩選,之后依次從大到小進(jìn)行獲取直到滿足skip+take也就是0+20=20條數(shù)據(jù)后,進(jìn)行直接拋棄剩余查詢返回結(jié)果,那么本次查詢基本上就是和單表查詢一樣,因?yàn)榛旧献疃嗫鐑蓮埍砘究梢詽M足要求(具體場(chǎng)景不一定)
          • 說明:假設(shè)last_id反解析出來的結(jié)果是2022-01-04 05:05:05那么可以基本上排除article_20220105,判斷并發(fā)連接數(shù)如果是1那么直接查詢article_20220104,如果不滿足繼續(xù)查詢article_20220103,直到查詢結(jié)果為20條如果并發(fā)連接數(shù)是2那么查詢[article_20220104、article_20220103]如果不滿足繼續(xù)下面兩張表直到獲取到結(jié)果為20條數(shù)據(jù),所以我們可以很清晰的了解其工作原理并且來優(yōu)化

          說明

          • 通過上述優(yōu)化可以保證流式聚合查詢?cè)陧樞虿樵兿碌母咝阅躉(1)
          • 通過上述優(yōu)化可以保證客戶端分片擁有最小化連接數(shù)控制
          • 設(shè)置合理的主鍵可以有效的解決我們?cè)诖髷?shù)據(jù)分片下的性能優(yōu)化

          實(shí)踐

          ShardingCore目前針對(duì)分片查詢進(jìn)行了不斷地優(yōu)化和盡可能的無業(yè)務(wù)代碼入侵來實(shí)現(xiàn)高性能分片查詢聚合。

          接下來我將為大家展示一款dotnet下唯一一款全自動(dòng)路由、多字段分片、無代碼入侵、高性能順序查詢的框架在傳統(tǒng)數(shù)據(jù)庫(kù)領(lǐng)域下的分片功能,如果你使用過我相信你一定會(huì)愛上他。

          第一步 安裝依賴

          #?ShardingCore核心框架?版本6.4.2.4+
          PM>?Install-Package?ShardingCore
          #?數(shù)據(jù)庫(kù)驅(qū)動(dòng)這邊選擇的是mysql的社區(qū)驅(qū)動(dòng)?efcore6最新版本即可
          PM>?Install-Package?Pomelo.EntityFrameworkCore.MySql

          第二步 添加對(duì)象和上下文

          有很多朋友問我一定需要使用fluentapi來使用ShardingCore嗎,只是個(gè)人喜好,這邊我才用dbset+attribute來實(shí)現(xiàn)

          //文章表
          [Table(nameof(Article))]
          public?class?Article
          {
          ????[MaxLength(128)]
          ????[Key]
          ????public?string?Id?{?get;?set;?}
          ????[MaxLength(128)]
          ????[Required]
          ????public?string?Title?{?get;?set;?}
          ????[MaxLength(256)]
          ????[Required]
          ????public?string?Content?{?get;?set;?}
          ????
          ????public?DateTime?PublishTime?{?get;?set;?}
          }
          context
          public?class?MyDbContext:AbstractShardingDbContext,IShardingTableDbContext
          {
          ????public?MyDbContext(DbContextOptions?options)?:?base(options)
          ????{
          添加會(huì)導(dǎo)致efcore?的model提前加載的方法如Database.xxxx
          ????}

          ????public?IRouteTail?RouteTail?{?get;?set;?}
          ????
          ????public?DbSet
          ?Articles?{?get;?set;?}
          }

          第三步 添加文章路由

          public?class?ArticleRoute:AbstractSimpleShardingDayKeyDateTimeVirtualTableRoute<Article>
          {
          ????public?override?void?Configure(EntityMetadataTableBuilder
          ?builder)
          ????{
          ????????builder.ShardingProperty(o?=>?o.PublishTime);
          ????}

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

          ????public?override?DateTime?GetBeginTime()
          ????{
          ????????return?new?DateTime(2022,?3,?1);
          ????}
          }

          到目前為止基本上Article已經(jīng)支持了按天分表

          第四步 添加查詢配置,讓框架知道我們是順序分表且定義分表的順序

          public?class?TailDayReverseComparer?:?IComparer<string>
          {
          ????public?int?Compare(string??x,?string??y)
          ????{
          ????????//程序默認(rèn)使用的是正序也就是按時(shí)間正序排序我們需要使用倒序所以直接調(diào)用原生的比較器然后乘以負(fù)一即可
          ????????return?Comparer<string>.Default.Compare(x,?y)?*?-1;
          ????}
          }
          //當(dāng)前查詢滿足的復(fù)核條件必須是單個(gè)分片對(duì)象的查詢,可以join普通非分片表
          public?class?ArticleEntityQueryConfiguration:IEntityQueryConfiguration<Article>
          {
          ????public?void?Configure(EntityQueryBuilder
          ?builder)
          ????{
          ????????//設(shè)置默認(rèn)的框架針對(duì)Article的排序順序,這邊設(shè)置的是倒序
          ????????builder.ShardingTailComparer(new?TailDayReverseComparer());
          ????????////如下設(shè)置和上述是一樣的效果讓框架真對(duì)Article的后綴排序使用倒序
          ????????//builder.ShardingTailComparer(Comparer.Default,?false);
          ????????
          ????????//簡(jiǎn)單解釋一下下面這個(gè)配置的意思
          ????????//第一個(gè)參數(shù)表名Article的哪個(gè)屬性是順序排序和Tail按天排序是一樣的這邊使用了PublishTime
          ????????//第二個(gè)參數(shù)表示對(duì)屬性PublishTime?asc時(shí)是否和上述配置的ShardingTailComparer一致,true表示一致,很明顯這邊是相反的因?yàn)槟J(rèn)已經(jīng)設(shè)置了tail排序是倒序
          ????????//第三個(gè)參數(shù)表示是否是Article屬性才可以,這邊設(shè)置的是名稱一樣也可以,因?yàn)榭紤]到匿名對(duì)象的select
          ????????builder.AddOrder(o?=>?o.PublishTime,?false,SeqOrderMatchEnum.Owner|SeqOrderMatchEnum.Named);
          ????????//這邊為了演示使用的id是簡(jiǎn)單的時(shí)間格式化所以和時(shí)間的配置一樣
          ????????builder.AddOrder(o?=>?o.Id,?false,SeqOrderMatchEnum.Owner|SeqOrderMatchEnum.Named);
          ????????//這邊設(shè)置如果本次查詢默認(rèn)沒有帶上述配置的order的時(shí)候才用何種排序手段
          ????????//第一個(gè)參數(shù)表示是否和ShardingTailComparer配置的一樣,目前配置的是倒序,也就是從最近時(shí)間開始查詢,如果是false就是從最早的時(shí)間開始查詢
          ????????//后面配置的是熔斷器,也就是復(fù)核熔斷條件的比如FirstOrDefault只需要滿足一個(gè)就可以熔斷
          ????????builder.AddDefaultSequenceQueryTrip(true,?CircuitBreakerMethodNameEnum.Enumerator,?CircuitBreakerMethodNameEnum.FirstOrDefault);

          ????????//這邊配置的是當(dāng)使用順序查詢配置的時(shí)候默認(rèn)開啟的連接數(shù)限制是多少,startup一開始可以設(shè)置一個(gè)默認(rèn)是當(dāng)前cpu的線程數(shù),這邊優(yōu)化到只需要一個(gè)線程即可,當(dāng)然如果跨表那么就是串行執(zhí)行
          ????????builder.AddConnectionsLimit(1,?LimitMethodNameEnum.Enumerator,?LimitMethodNameEnum.FirstOrDefault);
          ????}
          }

          第五步 添加配置到路由

          public?class?ArticleRoute:AbstractSimpleShardingDayKeyDateTimeVirtualTableRoute<Article>
          {
          ????//省略.....
          ????public?override?IEntityQueryConfiguration
          ?CreateEntityQueryConfiguration()
          ????{
          ????????return?new?ArticleEntityQueryConfiguration();
          ????}
          }

          第六步 startup配置

          var?builder?=?WebApplication.CreateBuilder(args);

          //?Add?services?to?the?container.
          ILoggerFactory?efLogger?=?LoggerFactory.Create(builder?=>
          {
          ????builder.AddFilter((category,?level)?=>?category?==?DbLoggerCategory.Database.Command.Name?&&?level?==?LogLevel.Information).AddConsole();
          });
          builder.Services.AddControllers();
          builder.Services.AddShardingDbContext()
          ????.AddEntityConfig(o?=>
          ????{
          ????????o.CreateShardingTableOnStart?=?true;
          ????????o.EnsureCreatedWithOutShardingTable?=?true;
          ????????o.AddShardingTableRoute();
          ????})
          ????.AddConfig(o?=>
          ????{
          ????????o.ConfigId?=?"c1";
          ????????o.UseShardingQuery((conStr,?b)?=>
          ????????{
          ????????????b.UseMySql(conStr,?new?MySqlServerVersion(new?Version())).UseLoggerFactory(efLogger);
          ????????});
          ????????o.UseShardingTransaction((conn,?b)?=>
          ????????{
          ????????????b.UseMySql(conn,?new?MySqlServerVersion(new?Version())).UseLoggerFactory(efLogger);
          ????????});
          ????????o.AddDefaultDataSource("ds0",?"server=127.0.0.1;port=3306;database=ShardingWaterfallDB;userid=root;password=root;");
          ????????o.ReplaceTableEnsureManager(sp?=>?new?MySqlTableEnsureManager());
          ????}).EnsureConfig();

          var?app?=?builder.Build();

          app.Services.GetRequiredService().Start();
          using?(var?scope?=?app.Services.CreateScope())
          {
          ????var?myDbContext?=?scope.ServiceProvider.GetRequiredService();
          ????if?(!myDbContext.Articles.Any())
          ????{
          ????????List
          ?articles?=?new?List
          ();
          ????????var?beginTime?=?new?DateTime(2022,?3,?1,?1,?1,1);
          ????????for?(int?i?=?0;?i?70;?i++)
          ????????{
          ????????????var?article?=?new?Article();
          ????????????article.Id?=?beginTime.ToString("yyyyMMddHHmmss");
          ????????????article.Title?=?"標(biāo)題"?+?i;
          ????????????article.Content?=?"內(nèi)容"?+?i;
          ????????????article.PublishTime?=?beginTime;
          ????????????articles.Add(article);
          ????????????beginTime=?beginTime.AddHours(2).AddMinutes(3).AddSeconds(4);
          ????????}
          ????????myDbContext.AddRange(articles);
          ????????myDbContext.SaveChanges();
          ????}
          }
          app.MapControllers();

          app.Run();

          第七步 編寫查詢表達(dá)式

          public?async?Task?Waterfall([FromQuery]?string?lastId,[FromQuery]int?take)
          {
          ????Console.WriteLine($"-----------開始查詢,lastId:[{lastId}],take:[{take}]-----------");
          ????var?list?=?await?_myDbContext.Articles.WhereIf(o?=>?String.Compare(o.Id,?lastId)?0,!string.IsNullOrWhiteSpace(lastId)).Take(take)..OrderByDescending(o?=>?o.PublishTime)ToListAsync();
          ????return?Ok(list);
          }

          運(yùn)行程序

          因?yàn)?7表是沒有的所以這次查詢會(huì)查詢07和06表,之后我們進(jìn)行下一次分頁(yè)傳入上次id

          因?yàn)闆]有對(duì)Article.Id進(jìn)行分片路由的規(guī)則編寫所以沒辦法進(jìn)行對(duì)id的過濾,那么接下來我們配置Id的分片規(guī)則

          首先針對(duì)ArticleRoute進(jìn)行代碼編寫

          public?class?ArticleRoute:AbstractSimpleShardingDayKeyDateTimeVirtualTableRoute<Article>
          {
          ????public?override?void?Configure(EntityMetadataTableBuilder
          ?builder)
          ????{
          ????????builder.ShardingProperty(o?=>?o.PublishTime);
          ????????builder.ShardingExtraProperty(o?=>?o.Id);
          ????}

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

          ????public?override?DateTime?GetBeginTime()
          ????{
          ????????return?new?DateTime(2022,?3,?1);
          ????}

          ????public?override?IEntityQueryConfiguration
          ?CreateEntityQueryConfiguration()
          ????{
          ????????return?new?ArticleEntityQueryConfiguration();
          ????}

          ????public?override?Expressionstring,?bool>>?GetExtraRouteFilter(object?shardingKey,?ShardingOperatorEnum?shardingOperator,?string?shardingPropertyName)
          ????{
          ????????switch?(shardingPropertyName)
          ????????{
          ????????????case?nameof(Article.Id):?return?GetArticleIdRouteFilter(shardingKey,?shardingOperator);
          ????????}

          ??????return?base.GetExtraRouteFilter(shardingKey,?shardingOperator,?shardingPropertyName);
          ????}
          ????///?
          ????///?文章id的路由
          ????///?

          ????///?
          ????///?
          ????///?
          ????private?Expressionstring,?bool>>?GetArticleIdRouteFilter(object?shardingKey,
          ????????ShardingOperatorEnum?shardingOperator)
          ????{
          ????????//將分表字段轉(zhuǎn)成訂單編號(hào)
          ????????var?id?=?shardingKey?.ToString()????string.Empty;
          ????????//判斷訂單編號(hào)是否是我們符合的格式
          ????????if?(!CheckArticleId(id,?out?var?orderTime))
          ????????{
          ????????????//如果格式不一樣就直接返回false那么本次查詢因?yàn)槭莂nd鏈接的所以本次查詢不會(huì)經(jīng)過任何路由,可以有效的防止惡意攻擊
          ????????????return?tail?=>?false;
          ????????}

          ????????//當(dāng)前時(shí)間的tail
          ????????var?currentTail?=?TimeFormatToTail(orderTime);
          ????????//因?yàn)槭前丛路直硭垣@取下個(gè)月的時(shí)間判斷id是否是在臨界點(diǎn)創(chuàng)建的
          ????????//var?nextMonthFirstDay?=?ShardingCoreHelper.GetNextMonthFirstDay(DateTime.Now);//這個(gè)是錯(cuò)誤的
          ????????var?nextMonthFirstDay?=?ShardingCoreHelper.GetNextMonthFirstDay(orderTime);
          ????????if?(orderTime.AddSeconds(10)?>?nextMonthFirstDay)
          ????????{
          ????????????var?nextTail?=?TimeFormatToTail(nextMonthFirstDay);
          ????????????return?DoArticleIdFilter(shardingOperator,?orderTime,?currentTail,?nextTail);
          ????????}
          ????????//因?yàn)槭前丛路直硭垣@取這個(gè)月月初的時(shí)間判斷id是否是在臨界點(diǎn)創(chuàng)建的
          ????????//if?(orderTime.AddSeconds(-10)?
          ????????if?(orderTime.AddSeconds(-10)?????????{
          ????????????//上個(gè)月tail
          ????????????var?previewTail?=?TimeFormatToTail(orderTime.AddSeconds(-10));

          ????????????return?DoArticleIdFilter(shardingOperator,?orderTime,?previewTail,?currentTail);
          ????????}

          ????????return?DoArticleIdFilter(shardingOperator,?orderTime,?currentTail,?currentTail);

          ????}

          ????private?Expressionstring
          ,?bool>>?DoArticleIdFilter(ShardingOperatorEnum?shardingOperator,?DateTime?shardingKey,?string?minTail,?string?maxTail)
          ????{
          ????????switch?(shardingOperator)
          ????????{
          ????????????case?ShardingOperatorEnum.GreaterThan:
          ????????????case?ShardingOperatorEnum.GreaterThanOrEqual:
          ????????????????{
          ????????????????????return?tail?=>?String.Compare(tail,?minTail,?StringComparison.Ordinal)?>=?0;
          ????????????????}

          ????????????case?ShardingOperatorEnum.LessThan:
          ????????????????{
          ????????????????????var?currentMonth?=?ShardingCoreHelper.GetCurrentMonthFirstDay(shardingKey);
          ????????????????????//處于臨界值?o=>o.time?
          ????????????????????if?(currentMonth?==?shardingKey)
          ????????????????????????return?tail?=>?String.Compare(tail,?maxTail,?StringComparison.Ordinal)?0
          ;
          ????????????????????return?tail?=>?String.Compare(tail,?maxTail,?StringComparison.Ordinal)?<=?0;
          ????????????????}
          ????????????case?ShardingOperatorEnum.LessThanOrEqual:
          ????????????????return?tail?=>?String.Compare(tail,?maxTail,?StringComparison.Ordinal)?<=?0;
          ????????????case?ShardingOperatorEnum.Equal:
          ????????????????{
          ????????????????????var?isSame?=?minTail?==?maxTail;
          ????????????????????if?(isSame)
          ????????????????????{
          ????????????????????????return?tail?=>?tail?==?minTail;
          ????????????????????}
          ????????????????????else
          ????????????????????{
          ????????????????????????return?tail?=>?tail?==?minTail?||?tail?==?maxTail;
          ????????????????????}
          ????????????????}
          ????????????default:
          ????????????????{
          ????????????????????return?tail?=>?true;
          ????????????????}
          ????????}
          ????}

          ????private?bool?CheckArticleId(string?orderNo,?out?DateTime?orderTime)
          ????{
          ????????//yyyyMMddHHmmss
          ????????if?(orderNo.Length?==?14)
          ????????{
          ????????????if?(DateTime.TryParseExact(orderNo,?"yyyyMMddHHmmss",?CultureInfo.InvariantCulture,
          ????????????????????DateTimeStyles.None,?out?var?parseDateTime))
          ????????????{
          ????????????????orderTime?=?parseDateTime;
          ????????????????return?true;
          ????????????}
          ????????}

          ????????orderTime?=?DateTime.MinValue;
          ????????return?false;
          ????}
          }

          完整路由:針對(duì)Id進(jìn)行多字段分片并且支持大于小于排序

          以上是多字段分片的優(yōu)化,詳情博客可以點(diǎn)擊這邊 .Net下你不得不看的分表分庫(kù)解決方案-多字段分片

          然后我們繼續(xù)查詢看看結(jié)果

          第三頁(yè)也是如此


          DEMO:https://github.com/xuejmnet/ShardingWaterfallApp


          總結(jié)

          當(dāng)前框架雖然是一個(gè)很年輕的框架,但是我相信我對(duì)其在分片領(lǐng)域的性能優(yōu)化應(yīng)該在.net現(xiàn)有的所有框架下找不出第二個(gè),并且框架整個(gè)也支持union all聚合,可以滿足列入group+first的特殊語(yǔ)句的查詢,又有很高的性能,一個(gè)不但是全自動(dòng)分片而且還是高性能框架擁有非常多的特性性能,目標(biāo)是榨干客戶端分片的最后一點(diǎn)性能。

          最后

          身位一個(gè)dotnet程序員我相信在之前我們的分片選擇方案除了mycatshardingsphere-proxy外沒有一個(gè)很好的分片選擇,但是我相信通過ShardingCore 的原理解析,你不但可以了解到大數(shù)據(jù)下分片的知識(shí)點(diǎn),更加可以參與到其中或者自行實(shí)現(xiàn)一個(gè),我相信只有了解了分片的原理dotnet才會(huì)有更好的人才和未來,我們不但需要優(yōu)雅的封裝,更需要原理的是對(duì)原理了解。

          我相信未來dotnet的生態(tài)會(huì)慢慢起來配上這近乎完美的語(yǔ)法

          轉(zhuǎn)自:薛家明

          鏈接:cnblogs.com/xuejiaming/p/15966501.html

          瀏覽 40
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  一区二区三区四区五区六区在线 | 99热热久久| 啪啪AV网站 | 天天插日日干 | 丁香六月色婷婷 |