ç§ãåå ããŠãã1幎äœãã§ã次ã®ã察話ããè¡ãããŸããã
.Net App ïŒEntity Frameworkãããããé¡ãããŸãã
Entity Framework ïŒç³ãèš³ãããŸããããç解ã§ããŸããã§ããã ã©ãããæå³ïŒ
.Net App ïŒã¯ãã10äžä»¶ã®ãã©ã³ã¶ã¯ã·ã§ã³ã®ã³ã¬ã¯ã·ã§ã³ãååŸããŸããã ãããŠä»ãããã«ç€ºãããŠãã蚌åžã®äŸ¡æ Œã®æ£ç¢ºããè¿
éã«ãã§ãã¯ããå¿
èŠããããŸãã
Entity Framework ïŒããããã£ãŠã¿ãŸããã...
.Net App ïŒã³ãŒãã¯æ¬¡ã®ãšããã§ãã
var query = from p in context.Prices join t in transactions on new { p.Ticker, p.TradedOn, p.PriceSourceId } equals new { t.Ticker, t.TradedOn, t.PriceSourceId } select p; query.ToList();
ãšã³ãã£ãã£ãã¬ãŒã ã¯ãŒã¯ ïŒ

ã¯ã©ã·ã㯠å€ãã®äººããã®ç¶æ³ã«ç²ŸéããŠãããšæããŸããããŒã«ã«ã³ã¬ã¯ã·ã§ã³ãšDbSetã® JOINã䜿çšããŠãããŒã¿ããŒã¹ããçŸããããã°ããæ€çŽ¢ããããšãã éåžžããã®çµéšã¯æ®å¿µã§ãã
ãã®èšäºïŒ ä»ã®èšäºã®ç¡æ翻蚳 ïŒã§ã¯ãäžé£ã®å®éšãè¡ãããã®å¶éãåé¿ããããã®ããŸããŸãªæ¹æ³ãè©ŠããŸãã ã³ãŒãïŒç°¡åãªïŒãæèãããããŒãšã³ãã®ãããªãã®ããããŸãã
ã¯ããã«
誰ããEntity Frameworkã«ã€ããŠç¥ã£ãŠãããå€ãã®äººãæ¯æ¥ããã䜿çšããŠããŸã ãå€ãã®äººãæ¯æ¥ããã䜿çšããŠããŸãããã®ä»ïŒãã ããããŒã«ã«ã³ã¬ã¯ã·ã§ã³ãšDbSetã® JOINããŒãã¯äŸç¶ãšããŠåŒ±ç¹ã§ãã
ææŠãã
äŸ¡æ Œã®ããŒã¿ããŒã¹ããããäŸ¡æ Œã®æ£ç¢ºæ§ã確èªããå¿
èŠããããã©ã³ã¶ã¯ã·ã§ã³ã®ã³ã¬ã¯ã·ã§ã³ããããšä»®å®ããŸãã ãããŠã次ã®ã³ãŒãããããšããŸãã
var localData = GetDataFromApiOrUser(); var query = from p in context.Prices join s in context.Securities on p.SecurityId equals s.SecurityId join t in localData on new { s.Ticker, p.TradedOn, p.PriceSourceId } equals new { t.Ticker, t.TradedOn, t.PriceSourceId } select p; var result = query.ToList();
ãã®ã³ãŒãã¯ã Entity Framework 6ã§ã¯ãŸã£ããæ©èœããŸããã Entity Framework Coreã§ã¯ -ããã¯æ©èœããŸããããã¹ãŠãã¯ã©ã€ã¢ã³ãåŽã§è¡ãããããŒã¿ããŒã¹ã«æ°çŸäžã®ã¬ã³ãŒããããå Žå-ããã¯ãªãã·ã§ã³ã§ã¯ãããŸããã
ç§ãèšã£ãããã«ãç§ã¯ãããåé¿ããããŸããŸãªæ¹æ³ãè©ŠããŸãã åçŽãªãã®ããè€éãªãã®ãŸã§ã ç§ã®å®éšã§ã¯ã次ã®ãªããžããªã®ã³ãŒãã䜿çšããŸã ã ã³ãŒãã¯ã CïŒ ã. Net Core ã EF Core ãããã³PostgreSQLã䜿çšããŠèšè¿°ãããŠããŸã ã
ãŸããè²»ãããæéãšã¡ã¢ãªæ¶è²»éã®ããã€ãã®ææšãæ®åœ±ããŸããã å
責äºé
ïŒãã¹ãã10å以äžå®è¡ãããå ŽåãäžæããŸããïŒå¶éã¯äžããã§ãïŒã ãã¹ããã·ã³Intel Core i5ã8 GB RAMãSSDã
DBã¹ããŒã
å¯äžã®3ã€ã®ããŒãã«ïŒ äŸ¡æ Œ ã èšŒåž ã äŸ¡æ ŒãœãŒã¹ ã äŸ¡æ Œ-1000äžãšã³ããªãå«ãŸããŠããŸãã
æ¹æ³1.ãã€ãŒã
ç°¡åãªãã®ããå§ããŠã次ã®ã³ãŒãã䜿çšããŸãããã
æ¹æ³1ã®ã³ãŒã var result = new List<Price>(); using (var context = CreateContext()) { foreach (var testElement in TestData) { result.AddRange(context.Prices.Where( x => x.Security.Ticker == testElement.Ticker && x.TradedOn == testElement.TradedOn && x.PriceSourceId == testElement.PriceSourceId)); } }
èãæ¹ã¯åçŽã§ããã«ãŒãã§ã¯ãããŒã¿ããŒã¹ããã¬ã³ãŒãã1ã€ãã€èªã¿åããçµæã®ã³ã¬ã¯ã·ã§ã³ã«è¿œå ããŸãã ãã®ã³ãŒãã«ã¯ãåçŽããšããå©ç¹ã1ã€ã ããããŸãã ãŸãã1ã€ã®æ¬ ç¹ã¯äœéã§ããããŒã¿ããŒã¹ã«ã€ã³ããã¯ã¹ãããå Žåã§ããã»ãšãã©ã®å ŽåãããŒã¿ããŒã¹ãµãŒããŒãšã®éä¿¡ãå¿
èŠã«ãªããŸãã ã¡ããªãã¯ã¯æ¬¡ã®ãšããã§ãã

ã¡ã¢ãªæ¶è²»ã¯ãããã§ãã 倧èŠæš¡ãªã³ã¬ã¯ã·ã§ã³ã«ã¯1åããããŸãã å§ããã®ã¯æªããããŸãããããã£ãšæ©ããããã§ãã
æ¹æ³2ïŒåçŽãªäžŠå
䞊ååŠçãè¿œå ããŠã¿ãŸãããã ã¢ã€ãã¢ã¯ãè€æ°ã®ã¹ã¬ããããããŒã¿ããŒã¹ã«ã¢ã¯ã»ã¹ããããšã§ãã
æ¹æ³2ã®ã³ãŒã var result = new ConcurrentBag<Price>(); var partitioner = Partitioner.Create(0, TestData.Count); Parallel.ForEach(partitioner, range => { var subList = TestData.Skip(range.Item1) .Take(range.Item2 - range.Item1) .ToList(); using (var context = CreateContext()) { foreach (var testElement in subList) { var query = context.Prices.Where( x => x.Security.Ticker == testElement.Ticker && x.TradedOn == testElement.TradedOn && x.PriceSourceId == testElement.PriceSourceId); foreach (var el in query) { result.Add(el); } } } });
çµæïŒ

å°ããªã³ã¬ã¯ã·ã§ã³ã®å Žåããã®ã¢ãããŒãã¯æåã®æ¹æ³ãããããã«é
ããªããŸãã æ倧ã®å Žå-2åé«éã§ãã èå³æ·±ãããšã«ã4ã€ã®ã¹ã¬ãããç§ã®ãã·ã³ã§çæãããŸããããããã¯4åã®é«éåã«ã¯ã€ãªãããŸããã§ããã ããã¯ãã¯ã©ã€ã¢ã³ãåŽãšãµãŒããŒåŽã®äž¡æ¹ã§ããã®æ¹æ³ã®ãªãŒããŒãããã倧ããããšã瀺åããŠããŸãã ã¡ã¢ãªæ¶è²»éã¯å¢å ããŸããããããã»ã©å€§ããã¯ãããŸããã
æ¹æ³3ïŒè€æ°ãå«ã
ä»ã®ããšãè©ŠããŠãã¿ã¹ã¯ã1ã€ã®ã¯ãšãªã«æžãããŠã¿ãŠãã ããã 次ã®ããã«å®è¡ã§ããŸãã
- äžæã®Ticker ã PriceSourceIdãããã³Dateå€ã®3ã€ã®ã³ã¬ã¯ã·ã§ã³ãæºåããŸã
- ãªã¯ãšã¹ããå®è¡ãã3ãå«ã
- çµæãããŒã«ã«ã§å確èªãã
æ¹æ³3ã®ã³ãŒã var result = new List<Price>(); using (var context = CreateContext()) {
ããã§ã®åé¡ã¯ãå®è¡æéãšè¿ãããããŒã¿ã®éããããŒã¿èªäœïŒã¯ãšãªãšããŒã¿ããŒã¹ã®äž¡æ¹ïŒã«å€§ããäŸåããŠããããšã§ãã ã€ãŸããå¿
èŠãªããŒã¿ã®ã¿ã®ã»ãããè¿ãããè¿œå ã®ã¬ã³ãŒãïŒ100å以äžïŒãè¿ãããŸãã
ããã¯ã次ã®äŸã䜿çšããŠèª¬æã§ããŸãã 次ã®ããŒã¿ã®è¡šããããšä»®å®ããŸãã

ãŸãã TradedOn = 2018-01-01ã® Ticker1ãšTradedOn = 2018-01-02ã® Ticker2ã®äŸ¡æ Œãå¿
èŠã ãšããŸãã
次ã«ã ãã£ãã«ãŒã®äžæã®å€=ïŒ Ticker1 ã Ticker2 ïŒ
ãããŠTradedOnã®äžæã®å€=ïŒ 2018-01-01ã2018-01-02 ïŒ
ãã ãããããã®çµã¿åããã«å®éã«å¯Ÿå¿ãããããçµæãšããŠ4ã€ã®ã¬ã³ãŒããè¿ãããŸãã æªãããšã¯ãããå€ãã®ãã£ãŒã«ãã䜿çšãããã»ã©ãçµæãšããŠäœåãªã¬ã³ãŒããååŸããå¯èœæ§ãé«ããªãããšã§ãã
ãã®ããããã®æ¹æ³ã§ååŸããããŒã¿ã¯ãã¯ã©ã€ã¢ã³ãåŽã§ããã«ãã£ã«ã¿ãªã³ã°ããå¿
èŠããããŸãã ãããŠãããæ倧ã®æ¬ ç¹ã§ãã
ã¡ããªãã¯ã¯æ¬¡ã®ãšããã§ãã

ã¡ã¢ãªæ¶è²»ã¯ã以åã®ãã¹ãŠã®æ¹æ³ãããæªãã§ãã èªã¿åãããè¡ã®æ°ã¯ãèŠæ±ãããæ°ã®äœåã«ããªããŸãã 倧èŠæš¡ãªã³ã¬ã¯ã·ã§ã³ã®ãã¹ãã¯ã10å以äžå®è¡ãããããäžæãããŸããã ãã®æ¹æ³ã¯ãããããŸããã
æ¹æ³4.è¿°èªãã«ããŒ
å察åŽã§è©ŠããŠã¿ãŸãããïŒå€ãè¯ãåŒ ã ãããã䜿çšããŠã次ã®åœ¢åŒã§1ã€ã®å€§ããªã¯ãšãªãäœæã§ããŸãã
⊠(.. AND .. AND ..) OR (.. AND .. AND ..) OR (.. AND .. AND ..) âŠ
ããã«ããã1ã€ã®ãªã¯ãšã¹ããäœæãã1åã®åŒã³åºãã«å¿
èŠãªããŒã¿ã®ã¿ãååŸã§ããããã«ãªãããšãæåŸ
ãããŸãã ã³ãŒãïŒ
æ¹æ³4ã®ã³ãŒã var result = new List<Price>(); using (var context = CreateContext()) { var baseQuery = from p in context.Prices join s in context.Securities on p.SecurityId equals s.SecurityId select new TestData() { Ticker = s.Ticker, TradedOn = p.TradedOn, PriceSourceId = p.PriceSourceId, PriceObject = p }; var tradedOnProperty = typeof(TestData).GetProperty("TradedOn"); var priceSourceIdProperty = typeof(TestData).GetProperty("PriceSourceId"); var tickerProperty = typeof(TestData).GetProperty("Ticker"); var paramExpression = Expression.Parameter(typeof(TestData)); Expression wholeClause = null; foreach (var td in TestData) { var elementClause = Expression.AndAlso( Expression.Equal( Expression.MakeMemberAccess( paramExpression, tradedOnProperty), Expression.Constant(td.TradedOn) ), Expression.AndAlso( Expression.Equal( Expression.MakeMemberAccess( paramExpression, priceSourceIdProperty), Expression.Constant(td.PriceSourceId) ), Expression.Equal( Expression.MakeMemberAccess( paramExpression, tickerProperty), Expression.Constant(td.Ticker)) )); if (wholeClause == null) wholeClause = elementClause; else wholeClause = Expression.OrElse(wholeClause, elementClause); } var query = baseQuery.Where( (Expression<Func<TestData, bool>>)Expression.Lambda( wholeClause, paramExpression)).Select(x => x.PriceObject); result.AddRange(query); }
ã³ãŒãã¯ã以åã®æ¹æ³ãããè€éã§ããããšãå€æããŸããã Expressionãæåã§æ§ç¯ããã®ã¯ ãæãç°¡åã§æéã®æäœã§ã¯ãããŸããã
ææšïŒ

äžæçãªçµæã¯ã以åã®æ¹æ³ãããããã«æªåããŸããã æ§ç¯äžã®ãªãŒããŒããããšããªãŒã®ééã¯ã1ã€ã®ãªã¯ãšã¹ãã䜿çšããããšã«ããã²ã€ã³ãããã¯ããã«å€§ããããšãå€æããããã§ãã
æ¹æ³5ïŒå
±æã¯ãšãªããŒã¿ããŒãã«
å¥ã®ãªãã·ã§ã³ãè©ŠããŠã¿ãŸãããïŒ
ãªã¯ãšã¹ããå®äºããããã«å¿
èŠãªããŒã¿ãæžã蟌ãããŒã¿ããŒã¹ã«æ°ããããŒãã«ãäœæããŸããïŒæé»çã«ã³ã³ããã¹ãã«æ°ããDbSetãå¿
èŠã§ãïŒã
ä»ãããªããå¿
èŠãªçµæãåŸãããã«ïŒ
- ãã©ã³ã¶ã¯ã·ã§ã³ãéå§
- ã¯ãšãªããŒã¿ãæ°ããããŒãã«ã«ã¢ããããŒããã
- ã¯ãšãªèªäœãå®è¡ããŸãïŒæ°ããããŒãã«ã䜿çšïŒ
- ãã©ã³ã¶ã¯ã·ã§ã³ã®ããŒã«ããã¯ïŒã¯ãšãªã®ããŒã¿ããŒãã«ãã¯ãªã¢ããããïŒ
ã³ãŒãã¯æ¬¡ã®ããã«ãªããŸãã
æ¹æ³5ã®ã³ãŒã var result = new List<Price>(); using (var context = CreateContext()) { context.Database.BeginTransaction(); var reducedData = TestData.Select(x => new SharedQueryModel() { PriceSourceId = x.PriceSourceId, Ticker = x.Ticker, TradedOn = x.TradedOn }).ToList();
æåã®ææšïŒ

ãã¹ãŠã®ãã¹ããæ©èœããè¿
éã«æ©èœããŸããïŒ ã¡ã¢ãªæ¶è²»ã蚱容ãããŸãã
ãããã£ãŠããã©ã³ã¶ã¯ã·ã§ã³ã䜿çšããããšã«ããããã®ããŒãã«ã¯è€æ°ã®ããã»ã¹ã§åæã«äœ¿çšã§ããŸãã ãããŠãããã¯å®éã®æ¢åã®ããŒãã«ã§ããããã Entity Frameworkã®ãã¹ãŠã®æ©èœã䜿çšã§ããŸããããŒã¿ãããŒãã«ã«ããŒããã JOINã䜿çšããŠã¯ãšãªãäœæããå®è¡ããã ãã§ãã äžèŠããããå¿
èŠãªãã®ã§ãããé倧ãªæ¬ ç¹ããããŸãã
- ç¹å®ã®çš®é¡ã®ã¯ãšãªçšã®ããŒãã«ãäœæããå¿
èŠããããŸã
- ãã©ã³ã¶ã¯ã·ã§ã³ã䜿çšããå¿
èŠããããŸãïŒãããŠãDBMSãªãœãŒã¹ãç¡é§ã«ããŸãïŒ
- ãããŠãèªãå¿
èŠããããšãã«äœããæžãå¿
èŠããããšãããŸãã«ã¢ã€ãã¢ã¯å¥åŠã«èŠããŸãã ãªãŒãã¬ããªã«ã§ã¯ãæ©èœããŸããã
ãããŠãæ®ãã¯ãã§ã«äœ¿çšã§ããå€ããå°ãªããæ©èœãããœãªã¥ãŒã·ã§ã³ã§ãã
æ¹æ³6. MemoryJoinæ¡åŒµæ©èœ
ããã§ã以åã®ã¢ãããŒããæ¹åããããšãã§ããŸãã èãã¯æ¬¡ã®ãšããã§ãã
- 1ã€ã®ã¿ã€ãã®ã¯ãšãªã«åºæã®ããŒãã«ã䜿çšãã代ããã«ãäžè¬çãªãªãã·ã§ã³ã䜿çšã§ããŸãã ã€ãŸãã shared_query_dataã®ãããªååã§ããŒãã«ãäœæããããã€ãã®Guidãã£ãŒã«ããããã€ãã®Long ãããã€ãã®Stringãªã©ãè¿œå ããŸãã åçŽãªååã䜿çšã§ããŸãïŒ Guid1 ã Guid2 ã String1 ã Long1 ã Date2ãªã©ã ãã®ããŒãã«ã¯ãã¯ãšãªã¿ã€ãã®95ïŒ
ã§äœ¿çšã§ããŸãã ããããã£åã¯ãåŸã§éžæããŒã¹ãã¯ãã£ãã䜿çšããŠã調æŽãã§ããŸãã
- 次ã«ã shared_query_dataã®DbSetãè¿œå ããå¿
èŠããããŸãã
- ããããããŒã¿ããŒã¹ã«ããŒã¿ãæžã蟌ã代ããã«ã VALUESæ§é ã䜿çšããŠå€ãæž¡ããšãããã©ãã§ããããã ã€ãŸããæçµçãªSQLã¯ãšãªã§ã¯ã shared_query_dataã«ã¢ã¯ã»ã¹ãã代ããã«ã VALUESã«ã¢ããŒã«ããå¿
èŠããããŸãã ã©ããã£ãŠããã®ïŒ
- Entity Framework Coreã§-FromSqlã䜿çšããã ãã§ãã
- Entity Framework 6ã§ã¯ã DbInterceptionã䜿çšããå¿
èŠããããŸãã ã€ãŸã ãå®è¡çŽåã«VALUESã³ã³ã¹ãã©ã¯ããè¿œå ããŠãçæãããSQLãå€æŽããŸãã ããã«ãããå¶éãçºçããŸããåäžã®ãªã¯ãšã¹ãã§ã¯ã VALUESæ§é ã¯1ã€ã ãã§ãã ããããããã¯åäœããŸãïŒ
- ããŒã¿ããŒã¹ã«æžã蟌ãäºå®ã¯ãªãã®ã§ãæåã®ã¹ãããã§shared_query_dataããŒãã«ãäœæããŸãããŸã£ããå¿
èŠãããŸãããïŒ åçïŒã¯ããå¿
èŠãããŸããããã¯ãšãªãäœæããããã«Entity FrameworkãããŒã¿ã¹ããŒã ãç¥ã£ãŠããå¿
èŠãããããã DbSetã¯ãŸã å¿
èŠã§ãã ããŒã¿ããŒã¹ã«ååšãããEntity Frameworkãåºæ¿ããããã ãã«äœ¿çšãããäžè¬åãããã¢ãã«ã«ã¯DbSetãå¿
èŠã§ããããããäœãããŠããã®ããããã£ãŠããããšãããããŸãã
IEnumerableãIQueryableã«å€æããäŸ- å
¥åã¯ã次ã®ã¿ã€ãã®ãªããžã§ã¯ãã®ã³ã¬ã¯ã·ã§ã³ãåãåããŸããã
class SomeQueryData { public string Ticker {get; set;} public DateTimeTradedOn {get; set;} public int PriceSourceId {get; set;} }
- String1 ã String2 ã Date1 ã Long1 ãªã©ã®ãã£ãŒã«ããæã€DbSetãèªç±ã«äœ¿çšã§ããŸã
- Tickerã String1 ã Date1ã® TradedOn ãããã³Long1ã®PriceSourceIdã«æ ŒçŽããŸã ïŒ intãšlongã®ãã£ãŒã«ããå¥ã
ã«äœæããªãããã«ã intã¯longã«ãããããŸãïŒ
- FromFrom + VALUESã¯æ¬¡ã®ããã«ãªããŸãã
var query = context.QuerySharedData.FromSql( "SELECT * FROM ( VALUES (1, 'Ticker1', @date1, @id1), (2, 'Ticker2', @date2, @id2) ) AS __gen_query_data__ (id, string1, date1, long1)")
- ããã§ãå
¥åæãšåãåã䜿çšããŠæ圱ãè¡ãã䟿å©ãªIQueryableãè¿ãããšãã§ããŸãã
return query.Select(x => new SomeQueryData() { Ticker = x.String1, TradedOn = x.Date1, PriceSourceId = (int)x.Long1 });
ç§ã¯ãã®ã¢ãããŒããå®è£
ããNuGetããã±ãŒãžEntityFrameworkCore.MemoryJoinãšããŠèšèšããããšãã§ããŸãã ïŒ ã³ãŒããå
¥æå¯èœã§ãïŒã ååã«Coreãšããåèªãå«ãŸããŠãããšããäºå®ã«ããããããã Entity Framework 6ããµããŒããããŠããŸãã ç§ã¯ãããMemoryJoinãšåŒã³ãŸããããå®éã«ã¯VALUESã³ã³ã¹ãã©ã¯ãã§ããŒã«ã«ããŒã¿ãDBMSã«éä¿¡ãããã¹ãŠã®äœæ¥ããã®äžã§è¡ãããŸãã
ã³ãŒãã¯æ¬¡ã®ãšããã§ãã
æ¹æ³6ã®ã³ãŒã var result = new List<Price>(); using (var context = CreateContext()) {
ææšïŒ

ããã¯ç§ãä»ãŸã§è©Šããäžã§æé«ã®çµæã§ãã ã³ãŒãã¯éåžžã«ã·ã³ãã«ã§ç°¡åã§ãããåæã«ãªãŒãã¬ããªã«ã§ãæ©èœããŠããŸããã
3ã€ã®èŠçŽ ãåä¿¡ããããã«çæããããªã¯ãšã¹ãã®äŸ SELECT "p"."PriceId", "p"."ClosePrice", "p"."OpenPrice", "p"."PriceSourceId", "p"."SecurityId", "p"."TradedOn", "t"."Ticker", "t"."TradedOn", "t"."PriceSourceId" FROM "Price" AS "p" INNER JOIN "Security" AS "s" ON "p"."SecurityId" = "s"."SecurityId" INNER JOIN ( SELECT "x"."string1" AS "Ticker", "x"."date1" AS "TradedOn", CAST("x"."long1" AS int4) AS "PriceSourceId" FROM ( SELECT * FROM ( VALUES (1, @__gen_q_p0, @__gen_q_p1, @__gen_q_p2), (2, @__gen_q_p3, @__gen_q_p4, @__gen_q_p5), (3, @__gen_q_p6, @__gen_q_p7, @__gen_q_p8) ) AS __gen_query_data__ (id, string1, date1, long1) ) AS "x" ) AS "t" ON (("s"."Ticker" = "t"."Ticker") AND ("p"."PriceSourceId" = "t"."PriceSourceId")
ããã§ã¯ãSelectã䜿çšããäžè¬åã¢ãã«ïŒãã£ãŒã«ãString1 ã Date1 ã Long1 ïŒããã³ãŒãã§äœ¿çšãããã¢ãã«ïŒãã£ãŒã«ãTicker ã TradedOn ã PriceSourceId ïŒã«ã©ã®ããã«å€ãããã確èªããããšãã§ããŸãã
ãã¹ãŠã®äœæ¥ã¯ãSQLãµãŒããŒã§1ã€ã®ã¯ãšãªã§å®è¡ãããŸãã ãããŠãããã¯å°ããªããããŒãšã³ãã§ãããæåã«è©±ããã ããã§ãããã®æ¹æ³ã䜿çšããã«ã¯ãç解ãšæ¬¡ã®æé ãå¿
èŠã§ãã
- è¿œå ã®DbSetãã³ã³ããã¹ãã«è¿œå ããå¿
èŠããããŸãïŒãã ããããŒãã«èªäœã¯çç¥ã§ããŸãïŒ
- ããã©ã«ãã§äœ¿çšãããäžè¬åã¢ãã«ã§ã¯ã Guid ã String ã Double ã Long ã Dateãªã©ã®ã¿ã€ãã®3ã€ã®ãã£ãŒã«ãã宣èšãããŠããŸãã èŠæ±ã¿ã€ãã®95ïŒ
ã«ã¯ããã§ååã§ãã ãŸãã20åã®ãã£ãŒã«ããæã€ãªããžã§ã¯ãã®ã³ã¬ã¯ã·ã§ã³ãFromLocalListã«æž¡ããšããªããžã§ã¯ããè€éãããããšã瀺ãäŸå€ãã¹ããŒãããŸãã ããã¯åŒ±ãå¶éã§ãããåé¿ããããšãã§ããŸã-ã¿ã€ãã宣èšããããã«å°ãªããšã100åã®ãã£ãŒã«ããè¿œå ã§ããŸãã ãã ããããå€ãã®ãã£ãŒã«ã-äœæ¥ãé
ããªããŸãã
- æè¡çãªè©³çŽ°ã¯ãç§ã®èšäºã«èšèŒãããŠããŸã ã
ãããã«
ãã®èšäºã§ã¯ãJOINããŒã«ã«ã³ã¬ã¯ã·ã§ã³ãšDbSetã®ãããã¯ã«é¢ããèãã瀺ããŸããã VALUESã䜿çšããç§ã®éçºã¯ãã³ãã¥ããã£ã«ãšã£ãŠèå³æ·±ããã®ã§ãããšæãããŸããã ãã®åé¡ãèªåã§è§£æ±ºãããšããå°ãªããšãç§ã¯ãã®ãããªã¢ãããŒãã«äŒããŸããã§ããã å人çã«ã¯ããã®æ¹æ³ã¯çŸåšã®ãããžã§ã¯ãã®ããã©ãŒãã³ã¹ã®åé¡ãå
æããã®ã«åœ¹ç«ã¡ãŸãããããããããªãã«ã圹ç«ã€ã§ãããã
誰ããMemoryJoinã®äœ¿çšã¯ "é£è§£"ã§ãããããã«éçºããå¿
èŠãããããããŸã§ã¯äœ¿çšããå¿
èŠããªããšèšãã§ãããã ããããŸãã«ç§ãéåžžã«çãããã£ãçç±ã§ãããã»ãŒäžå¹Žéãç§ã¯ãã®èšäºãæžããŸããã§ããã ç§ã¯ãããããç°¡åã«åäœããããšãæãã§ããããšã«åæããŸãïŒãã€ãããŸãããããšãæã¿ãŸãïŒããæé©åã¯ãžã¥ãã¢ã®ã¿ã¹ã¯ã§ã¯ãªãã£ãããšãèšããŸãã æé©åã§ã¯ãåžžã«ããŒã«ã®åäœãç解ããå¿
èŠããããŸãã ãããŠã æ倧 8åã®å éãåŸãããå ŽåïŒ Naive Parallel vs MemoryJoin ïŒã2ã€ã®ãã€ã³ããšããã¥ã¡ã³ããç¿åŸããŸãã
ãããŠæåŸã«ããã€ã¢ã°ã©ã ïŒ
è²»ãããæéã 10åæªæºã§ã¿ã¹ã¯ãå®äºããã¡ãœããã¯4ã€ã ãã§ããã10ç§æªæºã§ã¿ã¹ã¯ãå®äºããå¯äžã®æ¹æ³ã¯MemoryJoinã§ãã

ã¡ã¢ãªæ¶è²»ã Multiple Containsãé€ãããã¹ãŠã®ã¡ãœããã¯ã»ãŒåãã¡ã¢ãªæ¶è²»ã瀺ããŸããã ããã¯ãè¿ãããããŒã¿ã®éãåå ã§ãã

èªãã§ãããŠããããšãïŒ