我使用以下代码将记录插入SQL Server 2014中的表
using (SqlConnection conn = new SqlConnection(ConfigurationManager.AppSettings["myConnString"]))
{
conn.Execute("INSERT statement here", insertList);
}
insertList
是一个包含100万个项目的列表。我在i5桌面上测试了这个插件,在同一台机器上向SQL Server插入了一百万条记录大约需要65分钟。我不确定dapper是如何在幕后进行插入的。我当然不想打开和关闭数百万次数据库连接!
这是在小巧玲珑中进行批量插入的最佳方式,还是应该尝试其他方法,或者使用企业库使用普通的ADO.Net?
修改
事后看来,我知道使用ADO.Net会更好,所以会重新解释我的问题。我仍然想知道这是否是最适合小巧玲珑的人,或者我错过了一个更好的方法来在小巧玲珑本身做到这一点?
答案 0 :(得分:12)
如果性能是您之后的,那么我建议使用SqlBulkCopy而不是使用Dapper插入。请参阅此处进行一些性能比较:http://www.ikriv.com/dev/db/SqlInsert/SqlInsert.html
答案 1 :(得分:6)
基于Ehsan Sajjad的评论,其中一种方法是编写一个READINLY参数为user-defined TABLE type的存储过程。
假设您要批量插入包含名字和姓氏的联系人,您可以这样做: 1)创建表类型:
CREATE TYPE [dbo].[MyTableType] AS TABLE(
[FirstName] [varchar](50) NULL,
[LastName] [varchar](50) NULL
)
GO
2)现在创建一个使用上述表类型的存储过程:
CREATE PROC [dbo].[YourProc]
/*other params here*/
@Names AS MyTableType READONLY
AS
/* proc body here
*/
GO
3)在.NET端,将参数作为System.Data.SqlDbType.Structured传递 这通常涉及创建内存数据表,然后向其添加行,然后使用此DataTable对象作为@Names参数。 注意:DataTable被认为是内存密集型 - 请小心并对代码进行概要分析,以确保它不会导致服务器出现资源问题。
ALTENATIVE SOLUTION 使用此处列出的方法:https://stackoverflow.com/a/9947259/190476 该解决方案适用于DELETE,但也可以适用于插入或更新。
答案 2 :(得分:3)
以优异的性能插入的最佳免费方式是直接使用SqlBulkCopy
类,Alex和Andreas建议。
免责声明:我是该项目的所有者Dapper Plus
此项目不是免费的,但支持以下操作:
通过使用映射并允许输出像标识列一样的值。
// CONFIGURE & MAP entity
DapperPlusManager.Entity<Order>()
.Table("Orders")
.Identity(x => x.ID);
// CHAIN & SAVE entity
connection.BulkInsert(orders)
.AlsoInsert(order => order.Items);
.Include(x => x.ThenMerge(order => order.Invoice)
.AlsoMerge(invoice => invoice.Items))
.AlsoMerge(x => x.ShippingAddress);
答案 3 :(得分:0)
第一选择应该是 SQL批量复制,因为它可以安全地进行SQL注入。
但是,有一种方法可以大大提高性能。您可以将多个插入合并到一个SQL中,并且只有一个调用而不是多个调用。 所以代替这个:
您可以拥有:
批量插入用户的代码如下所示:
public async Task InsertInBulk(IList<string> userNames)
{
var sqls = GetSqlsInBatches(userNames);
using (var connection = new SqlConnection(ConnectionString))
{
foreach (var sql in sqls)
{
await connection.ExecuteAsync(sql);
}
}
}
private IList<string> GetSqlsInBatches(IList<string> userNames)
{
var insertSql = "INSERT INTO [Users] (Name, LastUpdatedAt) VALUES ";
var valuesSql = "('{0}', getdate())";
var batchSize = 1000;
var sqlsToExecute = new List<string>();
var numberOfBatches = (int)Math.Ceiling((double)userNames.Count / batchSize);
for (int i = 0; i < numberOfBatches; i++)
{
var userToInsert = userNames.Skip(i * batchSize).Take(batchSize);
var valuesToInsert = userToInsert.Select(u => string.Format(valuesSql, u));
sqlsToExecute.Add(insertSql + string.Join(',', valuesToInsert));
}
return sqlsToExecute;
}
此处提供了整篇文章和性能比较:http://www.michalbialecki.com/2019/05/21/bulk-insert-in-dapper/
答案 4 :(得分:-1)
我遇到了一个应该与 ADO、Entity 和 Dapper 一起使用的解决方案问题,因此制作了 this lib;它以
的形式生成批次IEnumerable<(string SqlQuery, IEnumerable<SqlParameter> SqlParameters)>
IEnumerable<(string SqlQuery, DynamicParameters DapperDynamicParameters)>
this link 包含说明。对 SQL 注入是安全的,因为使用参数而不是串联。
与 Dapper 一起使用:
using MsSqlHelpers;
var mapper = new MapperBuilder<Person>()
.SetTableName("People")
.AddMapping(person => person.FirstName, columnName: "Name")
.AddMapping(person => person.LastName, columnName: "Surename")
.AddMapping(person => person.DateOfBirth, columnName: "Birthday")
.Build();
var people = new List<Person>()
{
new Person() { FirstName = "John", LastName = "Lennon", DateOfBirth = new DateTime(1940, 10, 9) },
new Person() { FirstName = "Paul", LastName = "McCartney", DateOfBirth = new DateTime(1942, 6, 18) },
};
var connectionString = "Server=SERVER_ADDRESS;Database=DATABASE_NAME;User Id=USERNAME;Password=PASSWORD;";
var sqlQueriesAndDapperParameters = new MsSqlQueryGenerator().GenerateDapperParametrizedBulkInserts(mapper, people);
using (var sqlConnection = new SqlConnection(connectionString))
{
// Default batch size: 1000 rows or (2100-1) parameters per insert.
foreach (var (SqlQuery, DapperDynamicParameters) in sqlQueriesAndDapperParameters)
{
sqlConnection.Execute(SqlQuery, DapperDynamicParameters);
}
}