我有DataTable
,其中包含数十万行。在我的程序过程中,我向这个DataTable添加了几千行,这些行也需要添加到数据库中。我想尽快插入它们,而不是为每条记录创建一个INSERT语句。 MySQL LOAD INTO
命令不合适,因为我不想涉及任何外部CSV文件。
到目前为止我所做的是使用MySqlDataAdapter
并致电'更新'只有插入更改的方法,如下所示:
MySqlCommandBuilder commandBuilder = new MySqlCommandBuilder(adapter);
adapter.InsertCommand = commandBuilder.GetInsertCommand();
adapter.Update(myDataTable);
这也运行缓慢,所以我怀疑它们也是一次插入一行。我有什么选择?构建一个包含其中所有值的长INSERT语句,唯一的方法是什么?
答案 0 :(得分:6)
插入如下值: -
INSERT INTO tbl_name
(a,b,c)
VALUES
(1,2,3),
(4,5,6),
(7,8,9);
要优化插入速度,请将许多小型操作合并为一个 大手术。
答案 1 :(得分:2)
我看到的唯一解决方案是:
1)将DataTable转换为csv->你可以谷歌吧。
2)将其保存在临时目录的服务器端。
3)在这里使用MySqlBulkLoader
link来撰写有关它的文章。加载保存在临时目录中的文件。
4)之后从temp目录中删除文件。
答案 2 :(得分:0)
我不知道这是一个带参数的好方法,但效果很好 该方法接收“ParamDbList”列表(ParamDB的集合)并且每1000个寄存器或1900个参数(2000的限制)插入行。只需根据您的驱动器进行调整
public bool InsertBatch(System.Collections.Generic.List<ParamDbLIST> dados, string tabela)
{
if (dados.Count == 0)
return true;
string campos = "";
dados[0].ForEach(delegate(ParamDB p)
{
campos += (campos == "" ? "" : ", ") + "@" + p.sNOME + "#N#";
});
bool resultado = true;
//Insere de 999 a 999, que é o máximo q o sql server permite por vez
//Maximo de 2000 parametros
int k = 0;
while (k < dados.Count)
{
this.sql = new StringBuilder();
List<String> vals = new List<string>();
ParamDbLIST parametros_insert = new ParamDbLIST();
int c_sqls = 0;
int c_parametros = 0;
while (k < dados.Count && c_sqls < 1000 && c_parametros < 1900)
{
c_sqls++;
vals.Add("(" + campos.Replace("#N#", c_sqls.ToString()) + ")");
foreach (ParamDB p in dados[k])
{
p.sNOME += c_sqls.ToString();
parametros_insert.Add(p);
c_parametros++;
}
k++;
}
this.sql.Append("INSERT INTO " + tabela + "(" + campos.Replace("#N#", String.Empty).Replace("@", String.Empty) + ") VALUES " + String.Join(",", vals));
resultado = resultado && this.RunSQL(sql.ToString(), parametros_insert);
}
return resultado;
}
public class ParamDbLIST : System.Collections.ObjectModel.Collection<ParamDB>
{/*I have other stuff here, but this will work*/}
public class ParamDB
{
public string sNOME { get; set; }
public Object sVALOR { get; set; }}
记住方法 INSERT INTO tbl_name (A,B,C) VALUES (1,2,3), (4,5,6), (7,8,9); 每个命令限制为1000行。
我认为这里做的好事就是使用交易(为了安全)
您应该更改的方法是RunSQL
如果可以优化此方法,请告诉我
答案 3 :(得分:0)
不确定MySQL,但我发现使用sql server到目前为止最快的插入方式与@Rahautos类似,但是将值列表分开到单独的查询中。 我知道这听起来很奇怪但是这个速度提高了10倍,从每秒12到12000次插入。 不确定区别是什么。 而且交易也非常有用。
INSERT INTO tbl_name
(a,b,c)
VALUES
(1,2,3);
INSERT INTO tbl_name
(a,b,c);
VALUES
(4,5,6);
INSERT INTO tbl_name
(a,b,c);
VALUES
(7,8,9);
示例代码
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
var constring = (new SqlConnectionStringBuilder
{
DataSource = "someserver",
InitialCatalog = "12trunk",
IntegratedSecurity = true
}).ToString();
using (var con = new SqlConnection(constring))
{
con.Open();
using (var trans = con.BeginTransaction(isolationLevel: System.Data.IsolationLevel.ReadUncommitted) as SqlTransaction)
using (var cmd = new SqlCommand())
{
cmd.Transaction = trans;
cmd.Connection = con;
var start = DateTime.Now;
Console.WriteLine("Start = " + start);
const int inserts = 100000;
var builder = new StringBuilder();
cmd.CommandText = "delete from test";
for (int i = 0; i < inserts; i++)
{
Guid[] guids = new Guid[7];
for (int j = 0; j < 7; j++)
{
guids[j] = Guid.NewGuid();
}
var sql = $"insert into test (f0, f1, f2, f3, f4, f5, f6) values ('{guids[0]}', '{guids[1]}', '{guids[2]}','{guids[3]}', '{guids[4]}', '{guids[5]}', '{guids[6]}');\n";
builder.Append(sql);
if (i % 1000 == 0)
{
cmd.CommandText = builder.ToString();
cmd.ExecuteNonQuery();
builder.Clear();
}
}
cmd.CommandText = builder.ToString();
cmd.ExecuteNonQuery();
trans.Commit();
var ms = (DateTime.Now - start).TotalMilliseconds;
Console.WriteLine("Ms to run = " + ms);
Console.WriteLine("inserts per sec = " + inserts / (ms / 1000));
Console.ReadKey();
}
}
}
}
}
答案 4 :(得分:0)
我不确定MYSQl。 但是在MSSql Server中,在这种情况下,我们使用XML。 我们创建一个包含大量数据的xml,然后在数据库中使用Insert With Xml。
INSERT INTO [TBL_USER_INFO](NAME, EMAIL)
SELECT
Result.value('value','varchar(25)') as NAME,
Result.value('value','varchar(50)') as EMAIL
FROM
@input.nodes('/EmployeList/Employee') AS ABCD(Result)