为什么 Dapper 的批量插入比我预期的要慢很多?
生活随笔
收集整理的這篇文章主要介紹了
为什么 Dapper 的批量插入比我预期的要慢很多?
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
咨詢區
kenwarner:
我的項目中有一個批量插入的需求,我采用的是 Dapper 連接數據庫,下面是我的代碼。
var?members?=?new?List<Member>(); for?(int?i?=?0;?i?<?50000;?i++) {members.Add(new?Member(){Username?=?i.toString(),IsActive?=?true}); }using?(var?scope?=?new?TransactionScope()) {connection.Execute(@" insert?Member(Username,?IsActive) values(@Username,?@IsActive)",?members);scope.Complete(); }上面代碼插入需要 20s,插入量大概 2500/s,雖效果還行,但我在網上找的文章說可以做到 45k/s ,請問如何做到這么高的插入量?
回答區
Fredrik Ljung:
下面是我批量插入的最佳實踐,可以實現 50k 條數據 4s 搞定。
SqlTransaction?trans?=?connection.BeginTransaction();connection.Execute(@" insert?Member(Username,?IsActive) values(@Username,?@IsActive)",?members,?transaction:?trans);trans.Commit();CallumVass:
我實現了一個可批量插入的擴展方法,參考代碼如下:
public?static?class?DapperExtensions {public?static?async?Task?BulkInsert<T>(this?IDbConnection?connection,string?tableName,IReadOnlyCollection<T>?items,Dictionary<string,?Func<T,?object>>?dataFunc){const?int?MaxBatchSize?=?1000;const?int?MaxParameterSize?=?2000;var?batchSize?=?Math.Min((int)Math.Ceiling((double)MaxParameterSize?/?dataFunc.Keys.Count),?MaxBatchSize);var?numberOfBatches?=?(int)Math.Ceiling((double)items.Count?/?batchSize);var?columnNames?=?dataFunc.Keys;var?insertSql?=?$"INSERT?INTO?{tableName}?({string.Join(",?",?columnNames.Select(e?=>?$"[{e}]"))})?VALUES?";var?sqlToExecute?=?new?List<Tuple<string,?DynamicParameters>>();for?(var?i?=?0;?i?<?numberOfBatches;?i++){var?dataToInsert?=?items.Skip(i?*?batchSize).Take(batchSize);var?valueSql?=?GetQueries(dataToInsert,?dataFunc);sqlToExecute.Add(Tuple.Create($"{insertSql}{string.Join(",?",?valueSql.Item1)}",?valueSql.Item2));}foreach?(var?sql?in?sqlToExecute){await?connection.ExecuteAsync(sql.Item1,?sql.Item2,?commandTimeout:?int.MaxValue);}}private?static?Tuple<IEnumerable<string>,?DynamicParameters>?GetQueries<T>(IEnumerable<T>?dataToInsert,Dictionary<string,?Func<T,?object>>?dataFunc){var?parameters?=?new?DynamicParameters();return?Tuple.Create(dataToInsert.Select(e?=>?$"({string.Join(",?",?GenerateQueryAndParameters(e,?parameters,?dataFunc))})"),parameters);}private?static?IEnumerable<string>?GenerateQueryAndParameters<T>(T?entity,DynamicParameters?parameters,Dictionary<string,?Func<T,?object>>?dataFunc){var?paramTemplateFunc?=?new?Func<Guid,?string>(guid?=>?$"@p{guid.ToString().Replace("-",?"")}");var?paramList?=?new?List<string>();foreach?(var?key?in?dataFunc){var?paramName?=?paramTemplateFunc(Guid.NewGuid());parameters.Add(paramName,?key.Value(entity));paramList.Add(paramName);}return?paramList;} }然后可以像下面這樣使用。
await?dbConnection.BulkInsert(?"MySchemaName.MyTableName",?myCollectionOfItems,new?Dictionary<string,?Func<MyObjectToInsert,?object>>{{?"ColumnOne",?u?=>?u.ColumnOne?},{?"ColumnTwo",?u?=>?u.ColumnTwo?},...});點評區
在實際開發中,批量插入是一個非常常見的場景,用 事務 和 拼sql 都是高效的方式,我在實際開發中,用的是事務方式,學習了。
總結
以上是生活随笔為你收集整理的为什么 Dapper 的批量插入比我预期的要慢很多?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: System.Text.Json 自定义
- 下一篇: 如何让组织的KPI成为敏捷转型的推手而不