.Net C# Connector/Net 参数非常慢
.Net C# Connector/Net Parameters very slow
我正在使用 .net MYSQL 连接器:https://dev.mysql.com/downloads/file.php?id=455843 在 C# 中建立 mysql 连接。我已经在本地主机 Windows 上安装了 MariaDB 10.0。数据库引擎是 MyISAM。
问题:
我必须从现有的 csv 文件中插入大约 500k。为了使源代码更具可读性,我使用了准备好的语句。这花了我大约 38 秒来处理 1000 行。显然,这太过分了。注意:我什至没有尝试使用参数执行查询。
public void process(String commandText, Dictionary<string, string> param, int satz)
{
command.CommandText = commandText;
// command.Prepare();
Console.WriteLine(satz);
foreach(KeyValuePair<string, string> pair in param)
{
try {
command.Parameters.AddWithValue(pair.Key, pair.Value);
} catch (MySqlException ex)
{
/* some stuff */
}
}
// command.ExecuteNonQuery();
}
因为我不知道 AddWithValue 到底是做什么的,所以我检查了 sql 分析器。它告诉我他总共提出了 4 个请求 => 它与数据库无关。
一旦我将 commandText 更改为不带参数的直接 INSERT 语句,该函数就用了大约 0.8 秒。
public void process(String commandText, Dictionary<string, string> param, int satz)
{
command.CommandText = commandText;
// command.Prepare();
Console.WriteLine(satz);
foreach(KeyValuePair<string, string> pair in param)
{
try {
//command.Parameters.AddWithValue(pair.Key, pair.Value);
//command.Parameters[pair.Key].DbType = System.Data.DbType.AnsiString;
} catch (MySqlException ex)
{
/*if (ex.ErrorCode == -2147467259)
continue;
else
throw ex;*/
}
}
command.ExecuteNonQuery();
}
这是生成的SQL查询
public void process210(String[] attributes)
{
if (++line210 > 1000) return;
Console.Write(line210+" : ");
// String commandText = "INSERT INTO Programm (Serien_Nr, Prog_Schluessel, Prog_Name, Preisfeld, Front_Tiefe, Preisgruppe, Preisfeld_Block, Lieferbar_ab, Lieferbar_bis, Frontauspraegungs_ID, Frontgruppe, Var_Familien_Nr, Varianten_Art_Front, Var_Schluessel_Front, Mindest_Lieferzeit, Hersteller_ID) values (@Serien_Nr, @Prog_Schluessel, @Prog_Name, @Preisfeld, @Front_Tiefe, @Preisgruppe, @Preisfeld_Block, @Lieferbar_ab, @Lieferbar_bis, @Frontauspraegungs_ID, @Frontgruppe, @Var_Familien_Nr, @Varianten_Art_Front, @Var_Schluessel_Front, @Mindest_Lieferzeit, @Hersteller_ID) ;";
String programm_Serien_Nr = attributes[1].Replace("\"", "").Replace(";", "");
String programm_Prog_Schluessel = attributes[2].Replace("\", "").Replace("\"", "").Replace(";", "");
String programm_Prog_Name = attributes[3].Replace("\", "").Replace("\"", "").Replace(";", "");
String programm_Preisfeld = attributes[4].Replace("\", "").Replace("\"", "").Replace(";", "");
String programm_Front_Tiefe = attributes[5].Replace("\", "").Replace("\"", "").Replace(";", "");
String programm_Preisgruppe = attributes[6].Replace("\", "").Replace("\"", "").Replace(";", "");
String programm_Preisfeld_Block = attributes[7].Replace("\", "").Replace("\"", "").Replace(";", "");
String programm_Lieferbar_Ab = attributes[8].Replace("\", "").Replace("\"", "").Replace(";", "");
String programm_Lieferbar_Bis = attributes[9].Replace("\", "").Replace("\"", "").Replace(";", "");
String programm_Frontauspraegungs_ID = attributes[10].Replace("\", "").Replace("\"", "").Replace(";", "");
String programm_Frontgruppe = attributes[11].Replace("\", "").Replace("\"", "").Replace(";", "");
String programm_Var_Familien_Nr = attributes[12].Replace("\", "").Replace("\"", "").Replace(";", "");
String programm_Varianten_Art_Front = attributes[13].Replace("\", "").Replace("\"", "").Replace(";", "");
String programm_Var_Schluessel_Front = attributes[14].Replace("\", "").Replace("\"", "").Replace(";", "");
String programm_Mindest_Lieferzeit = attributes[15].Replace(";", "").Replace("\", "").Replace("\"", "");
String commandText = "INSERT INTO Programm (Serien_Nr, Prog_Schluessel, Prog_Name, Preisfeld, Front_Tiefe, Preisgruppe, Preisfeld_Block, Lieferbar_ab, Lieferbar_bis, Frontauspraegungs_ID, Frontgruppe, Var_Familien_Nr, Varianten_Art_Front, Var_Schluessel_Front, Mindest_Lieferzeit, Hersteller_ID) values (\""+ programm_Serien_Nr + "\", \"" + programm_Prog_Schluessel + "\", \"" + programm_Prog_Name + "\", \"" + programm_Preisfeld + "\", \"" + programm_Front_Tiefe + "\", \"" + programm_Preisgruppe + "\", \"" + programm_Preisfeld_Block + "\", \"" + programm_Lieferbar_Ab + "\", \"" + programm_Lieferbar_Bis + "\", \"" + programm_Frontauspraegungs_ID + "\", \"" + programm_Frontgruppe + "\", \"" + programm_Var_Familien_Nr + "\", \"" + programm_Varianten_Art_Front + "\", \"" + programm_Var_Schluessel_Front + "\", \"" + programm_Mindest_Lieferzeit + "\", \"" + hersteller_id + "\") ;";
Dictionary<string, string> dictionary = new Dictionary<string, string>();
dictionary.Add("@Serien_Nr", attributes[1]);
dictionary.Add("@Prog_Schluessel", attributes[2]);
dictionary.Add("@Prog_Name", attributes[3]);
dictionary.Add("@Preisfeld", attributes[4]);
dictionary.Add("@Front_Tiefe", attributes[5]);
dictionary.Add("@Preisgruppe", attributes[6]);
dictionary.Add("@Preisfeld_Block", attributes[7]);
dictionary.Add("@Lieferbar_ab", attributes[8]);
dictionary.Add("@Lieferbar_bis", attributes[9]);
dictionary.Add("@Frontauspraegungs_ID", attributes[10]);
dictionary.Add("@Frontgruppe", attributes[11]);
dictionary.Add("@Var_Familien_Nr", attributes[12]);
dictionary.Add("@Varianten_Art_Front", attributes[13]);
dictionary.Add("@Var_Schluessel_Front", attributes[14]);
dictionary.Add("@Mindest_Lieferzeit", attributes[15]);
dictionary.Add("@Hersteller_ID", hersteller_id);
process(commandText, dictionary, 210);
}
知道为什么它这么慢吗?我真的很想使用准备好的语句,因为它大大提高了代码的可读性。
编辑:
就像 Andy Nichols 所说的那样,我忘记在执行后从 MysqlCommand 刷新集合。谢谢。
解决方案是这样的
public static void process(String commandText, Dictionary<string, string> param, int satz)
{
command = new MySqlCommand();
command.Connection = con;
command.CommandText = commandText;
command.Prepare();
foreach (KeyValuePair<string, string> pair in param)
{
try {
command.Parameters.AddWithValue(pair.Key, pair.Value);
} catch (MySqlException ex)
{
/* stuff */
}
}
command.ExecuteNonQuery();
}
如评论中所述。
命令对象在循环中重复使用 - 每行一个输入语句。在每次迭代中,您都为 16 个参数中的每一个调用 command.Parameters.AddWithValue
。这意味着您的参数集合每行增加 16 个。
要解决此问题,您需要:
在添加参数的 foreach 循环之前清除参数
或
在第一次创建命令对象时设置没有值的参数。然后,在每次迭代中设置值。如果名称和数据类型不变,实际上不需要每次都清除并重新添加参数。
我正在使用 .net MYSQL 连接器:https://dev.mysql.com/downloads/file.php?id=455843 在 C# 中建立 mysql 连接。我已经在本地主机 Windows 上安装了 MariaDB 10.0。数据库引擎是 MyISAM。
问题:
我必须从现有的 csv 文件中插入大约 500k。为了使源代码更具可读性,我使用了准备好的语句。这花了我大约 38 秒来处理 1000 行。显然,这太过分了。注意:我什至没有尝试使用参数执行查询。
public void process(String commandText, Dictionary<string, string> param, int satz)
{
command.CommandText = commandText;
// command.Prepare();
Console.WriteLine(satz);
foreach(KeyValuePair<string, string> pair in param)
{
try {
command.Parameters.AddWithValue(pair.Key, pair.Value);
} catch (MySqlException ex)
{
/* some stuff */
}
}
// command.ExecuteNonQuery();
}
因为我不知道 AddWithValue 到底是做什么的,所以我检查了 sql 分析器。它告诉我他总共提出了 4 个请求 => 它与数据库无关。
一旦我将 commandText 更改为不带参数的直接 INSERT 语句,该函数就用了大约 0.8 秒。
public void process(String commandText, Dictionary<string, string> param, int satz)
{
command.CommandText = commandText;
// command.Prepare();
Console.WriteLine(satz);
foreach(KeyValuePair<string, string> pair in param)
{
try {
//command.Parameters.AddWithValue(pair.Key, pair.Value);
//command.Parameters[pair.Key].DbType = System.Data.DbType.AnsiString;
} catch (MySqlException ex)
{
/*if (ex.ErrorCode == -2147467259)
continue;
else
throw ex;*/
}
}
command.ExecuteNonQuery();
}
这是生成的SQL查询
public void process210(String[] attributes)
{
if (++line210 > 1000) return;
Console.Write(line210+" : ");
// String commandText = "INSERT INTO Programm (Serien_Nr, Prog_Schluessel, Prog_Name, Preisfeld, Front_Tiefe, Preisgruppe, Preisfeld_Block, Lieferbar_ab, Lieferbar_bis, Frontauspraegungs_ID, Frontgruppe, Var_Familien_Nr, Varianten_Art_Front, Var_Schluessel_Front, Mindest_Lieferzeit, Hersteller_ID) values (@Serien_Nr, @Prog_Schluessel, @Prog_Name, @Preisfeld, @Front_Tiefe, @Preisgruppe, @Preisfeld_Block, @Lieferbar_ab, @Lieferbar_bis, @Frontauspraegungs_ID, @Frontgruppe, @Var_Familien_Nr, @Varianten_Art_Front, @Var_Schluessel_Front, @Mindest_Lieferzeit, @Hersteller_ID) ;";
String programm_Serien_Nr = attributes[1].Replace("\"", "").Replace(";", "");
String programm_Prog_Schluessel = attributes[2].Replace("\", "").Replace("\"", "").Replace(";", "");
String programm_Prog_Name = attributes[3].Replace("\", "").Replace("\"", "").Replace(";", "");
String programm_Preisfeld = attributes[4].Replace("\", "").Replace("\"", "").Replace(";", "");
String programm_Front_Tiefe = attributes[5].Replace("\", "").Replace("\"", "").Replace(";", "");
String programm_Preisgruppe = attributes[6].Replace("\", "").Replace("\"", "").Replace(";", "");
String programm_Preisfeld_Block = attributes[7].Replace("\", "").Replace("\"", "").Replace(";", "");
String programm_Lieferbar_Ab = attributes[8].Replace("\", "").Replace("\"", "").Replace(";", "");
String programm_Lieferbar_Bis = attributes[9].Replace("\", "").Replace("\"", "").Replace(";", "");
String programm_Frontauspraegungs_ID = attributes[10].Replace("\", "").Replace("\"", "").Replace(";", "");
String programm_Frontgruppe = attributes[11].Replace("\", "").Replace("\"", "").Replace(";", "");
String programm_Var_Familien_Nr = attributes[12].Replace("\", "").Replace("\"", "").Replace(";", "");
String programm_Varianten_Art_Front = attributes[13].Replace("\", "").Replace("\"", "").Replace(";", "");
String programm_Var_Schluessel_Front = attributes[14].Replace("\", "").Replace("\"", "").Replace(";", "");
String programm_Mindest_Lieferzeit = attributes[15].Replace(";", "").Replace("\", "").Replace("\"", "");
String commandText = "INSERT INTO Programm (Serien_Nr, Prog_Schluessel, Prog_Name, Preisfeld, Front_Tiefe, Preisgruppe, Preisfeld_Block, Lieferbar_ab, Lieferbar_bis, Frontauspraegungs_ID, Frontgruppe, Var_Familien_Nr, Varianten_Art_Front, Var_Schluessel_Front, Mindest_Lieferzeit, Hersteller_ID) values (\""+ programm_Serien_Nr + "\", \"" + programm_Prog_Schluessel + "\", \"" + programm_Prog_Name + "\", \"" + programm_Preisfeld + "\", \"" + programm_Front_Tiefe + "\", \"" + programm_Preisgruppe + "\", \"" + programm_Preisfeld_Block + "\", \"" + programm_Lieferbar_Ab + "\", \"" + programm_Lieferbar_Bis + "\", \"" + programm_Frontauspraegungs_ID + "\", \"" + programm_Frontgruppe + "\", \"" + programm_Var_Familien_Nr + "\", \"" + programm_Varianten_Art_Front + "\", \"" + programm_Var_Schluessel_Front + "\", \"" + programm_Mindest_Lieferzeit + "\", \"" + hersteller_id + "\") ;";
Dictionary<string, string> dictionary = new Dictionary<string, string>();
dictionary.Add("@Serien_Nr", attributes[1]);
dictionary.Add("@Prog_Schluessel", attributes[2]);
dictionary.Add("@Prog_Name", attributes[3]);
dictionary.Add("@Preisfeld", attributes[4]);
dictionary.Add("@Front_Tiefe", attributes[5]);
dictionary.Add("@Preisgruppe", attributes[6]);
dictionary.Add("@Preisfeld_Block", attributes[7]);
dictionary.Add("@Lieferbar_ab", attributes[8]);
dictionary.Add("@Lieferbar_bis", attributes[9]);
dictionary.Add("@Frontauspraegungs_ID", attributes[10]);
dictionary.Add("@Frontgruppe", attributes[11]);
dictionary.Add("@Var_Familien_Nr", attributes[12]);
dictionary.Add("@Varianten_Art_Front", attributes[13]);
dictionary.Add("@Var_Schluessel_Front", attributes[14]);
dictionary.Add("@Mindest_Lieferzeit", attributes[15]);
dictionary.Add("@Hersteller_ID", hersteller_id);
process(commandText, dictionary, 210);
}
知道为什么它这么慢吗?我真的很想使用准备好的语句,因为它大大提高了代码的可读性。
编辑:
就像 Andy Nichols 所说的那样,我忘记在执行后从 MysqlCommand 刷新集合。谢谢。
解决方案是这样的
public static void process(String commandText, Dictionary<string, string> param, int satz)
{
command = new MySqlCommand();
command.Connection = con;
command.CommandText = commandText;
command.Prepare();
foreach (KeyValuePair<string, string> pair in param)
{
try {
command.Parameters.AddWithValue(pair.Key, pair.Value);
} catch (MySqlException ex)
{
/* stuff */
}
}
command.ExecuteNonQuery();
}
如评论中所述。
命令对象在循环中重复使用 - 每行一个输入语句。在每次迭代中,您都为 16 个参数中的每一个调用 command.Parameters.AddWithValue
。这意味着您的参数集合每行增加 16 个。
要解决此问题,您需要:
在添加参数的 foreach 循环之前清除参数
或
在第一次创建命令对象时设置没有值的参数。然后,在每次迭代中设置值。如果名称和数据类型不变,实际上不需要每次都清除并重新添加参数。