从 C# 执行 SQL 命令的最快方法
Fastest way to execute a SQL command from C#
我正在努力使用 SQL 服务器数据库,我想在其中保留我添加来自多个供应商的价格的参考。
我正在读取 .xlsx
文件参考和价格,并将价格存储在 SQL 服务器数据库中。我必须检查 ref 是否已经存在 - 如果是,我更新,如果不存在,那么我需要插入。
一个 ref 大约需要 100-120 毫秒才能 inserted/updated 进入数据库 - 大部分时间被 ExecuteReader
消耗(也尝试使用 ExecuteNonQuery
)大约 70 毫秒。
我的问题:是否有可能使其更快?对于 1.000.000 个参考,更新可能需要大约 33 小时...
代码如下:
string ref;
string price;
cs.Open();
for (int i = 1; i < lastRow; i++)
{
ref = (xlWorksheet.Cells[i, 1] as Excel.Range).Value2.ToString();
price = (xlWorksheet.Cells[i, 2] as Excel.Range).Value2.ToString();
price = price.Replace(',', '.');
command = new SqlCommand("UPDATE ORG SET "+supplierName+" = '" + price + "' WHERE REFERENCJE = '" + ref + "'"
+ " IF @@ROWCOUNT = 0"
+ " INSERT INTO ORG(" + supplierName + ", REFERENCJE)"
+ " VALUES('" + price + "', '" + ref + "') ", cs);
command.ExecuteReader().Close(); //consume circa 75ms
}
cs.Close();
对不起我的英语。
问题解决了(当然感谢你们)
我你建议 - 我决定创建临时 table 并将所有导入的数据放在那里。接下来将它与主 table 合并。
此外,我将导入从 .xlsx
从 1 项更改为一次 2 列和 100 行的范围,我将其放入 DataTable
并使用 batch
方法插入。
也许我的解决方案会对某人有所帮助。我在不到 15 分钟的时间内更新了 1.000.000 个条目。
代码:
//checking if temp table exists, if not creates it
command = new SqlCommand("IF NOT (EXISTS (SELECT *"
+ " FROM INFORMATION_SCHEMA.TABLES"
+ " WHERE TABLE_NAME = '" + tempTable + "')) CREATE TABLE " + tempTable + "(REFERENCJE VARCHAR(255), PRODUCENT VARCHAR (255), price VARCHAR(255));", cs);
cs.Open();
command.ExecuteNonQuery();
cs.Close();
for (int i = 1; ; i++)
{
//get 2 columns from Excel file with 100 rows and store it in array
Excel.Range range = null;
if (i * 100 > lastRow)
range = xlWorksheet.Range["A" + ((i - 1) * 100 + 1), "B" + lastRow];
else
range = xlWorksheet.Range["A" + ((i - 1) * 100 + 1), "B" + (i * 100)];
Array myValues = (System.Array)range.Cells.Value2;
//rewrites Array to DataTable
for (int j = 1; j < myValues.Length / 2; j++)
{
rowInsert = tabelaInsert.NewRow();
rowInsert["ref"] = myValues.GetValue(j, 1).ToString();
rowInsert["price"] = myValues.GetValue(j, 2).ToString();
rowInsert["prod"] = orgProd;
tabelaInsert.Rows.Add(rowInsert);
}
batchowanieInsert(tabelaInsert, supplierName, tempTable);
tabelaInsert.Clear();
if (i * 100 > lastRow)
break;
}
//SQL MERGE 2 tables
command = new SqlCommand("MERGE ORG AS TARGET"
+ " USING " + tempTable + " AS SOURCE"
+ " ON(TARGET.REFERENCJE = SOURCE.REFERENCJE)"
+ " WHEN MATCHED AND TARGET." + supplierName + " <> SOURCE.CENA THEN"
+ " UPDATE SET TARGET." + supplierName + " = SOURCE.CENA,"
+ " TARGET.PRODUCENT = SOURCE.PRODUCENT"
+ " WHEN NOT MATCHED BY TARGET THEN"
+ " INSERT(REFERENCJE, PRODUCENT, " + supplierName + ")"
+ " VALUES(SOURCE.REFERENCJE, SOURCE.PRODUCENT, SOURCE.CENA);", cs);
cs.Open();
command.ExecuteNonQuery();
cs.Close();
//DELETING temp table
command = new SqlCommand("DROP TABLE " + tempTable, cs);
cs.Open();
command.ExecuteNonQuery();
cs.Close();
//batchowanieInsert function
public void batchowanieInsert(DataTable tabela, string supplierName, string tempTable)
{
da.UpdateBatchSize = tabela.Rows.Count;
da.InsertCommand = new SqlCommand("INSERT INTO " + tempTable + " (REFERENCJE, PRODUCENT, CENA) VALUES (@REFERENCJE, @PRODUCENT, @CENA)", cs);
da.InsertCommand.Parameters.Add("@REFERENCJE", SqlDbType.VarChar, 20, "ref");
da.InsertCommand.Parameters.Add("@PRODUCENT", SqlDbType.VarChar, 20, "prod");
da.InsertCommand.Parameters.Add("@CENA", SqlDbType.VarChar, 20, "price");
da.InsertCommand.UpdatedRowSource = UpdateRowSource.None;
da.Update(tabela);
}
循环遍历单个 Excel 单元格总是会导致效率低下。我会建议:
将数据导入 SQL table 然后使用 SELECT 语句执行检查而不是 @ @ROWCOUNT(记住@@ROWCOUNT 是从服务器返回的消息,并针对您要插入的每一行传输到客户端)。使用@NOCOUN 来静音服务器回复。
或者考虑使用 CSV 而不是 Excel 工作簿。
将您的所有数据导入临时文件table(您可以使用多个 INSERT 语句,SqlServer 对大约 100 条记录的批处理性能更好)
更新存在的地方
在不存在的地方插入
我正在努力使用 SQL 服务器数据库,我想在其中保留我添加来自多个供应商的价格的参考。
我正在读取 .xlsx
文件参考和价格,并将价格存储在 SQL 服务器数据库中。我必须检查 ref 是否已经存在 - 如果是,我更新,如果不存在,那么我需要插入。
一个 ref 大约需要 100-120 毫秒才能 inserted/updated 进入数据库 - 大部分时间被 ExecuteReader
消耗(也尝试使用 ExecuteNonQuery
)大约 70 毫秒。
我的问题:是否有可能使其更快?对于 1.000.000 个参考,更新可能需要大约 33 小时...
代码如下:
string ref;
string price;
cs.Open();
for (int i = 1; i < lastRow; i++)
{
ref = (xlWorksheet.Cells[i, 1] as Excel.Range).Value2.ToString();
price = (xlWorksheet.Cells[i, 2] as Excel.Range).Value2.ToString();
price = price.Replace(',', '.');
command = new SqlCommand("UPDATE ORG SET "+supplierName+" = '" + price + "' WHERE REFERENCJE = '" + ref + "'"
+ " IF @@ROWCOUNT = 0"
+ " INSERT INTO ORG(" + supplierName + ", REFERENCJE)"
+ " VALUES('" + price + "', '" + ref + "') ", cs);
command.ExecuteReader().Close(); //consume circa 75ms
}
cs.Close();
对不起我的英语。
问题解决了(当然感谢你们)
我你建议 - 我决定创建临时 table 并将所有导入的数据放在那里。接下来将它与主 table 合并。
此外,我将导入从 .xlsx
从 1 项更改为一次 2 列和 100 行的范围,我将其放入 DataTable
并使用 batch
方法插入。
也许我的解决方案会对某人有所帮助。我在不到 15 分钟的时间内更新了 1.000.000 个条目。
代码:
//checking if temp table exists, if not creates it
command = new SqlCommand("IF NOT (EXISTS (SELECT *"
+ " FROM INFORMATION_SCHEMA.TABLES"
+ " WHERE TABLE_NAME = '" + tempTable + "')) CREATE TABLE " + tempTable + "(REFERENCJE VARCHAR(255), PRODUCENT VARCHAR (255), price VARCHAR(255));", cs);
cs.Open();
command.ExecuteNonQuery();
cs.Close();
for (int i = 1; ; i++)
{
//get 2 columns from Excel file with 100 rows and store it in array
Excel.Range range = null;
if (i * 100 > lastRow)
range = xlWorksheet.Range["A" + ((i - 1) * 100 + 1), "B" + lastRow];
else
range = xlWorksheet.Range["A" + ((i - 1) * 100 + 1), "B" + (i * 100)];
Array myValues = (System.Array)range.Cells.Value2;
//rewrites Array to DataTable
for (int j = 1; j < myValues.Length / 2; j++)
{
rowInsert = tabelaInsert.NewRow();
rowInsert["ref"] = myValues.GetValue(j, 1).ToString();
rowInsert["price"] = myValues.GetValue(j, 2).ToString();
rowInsert["prod"] = orgProd;
tabelaInsert.Rows.Add(rowInsert);
}
batchowanieInsert(tabelaInsert, supplierName, tempTable);
tabelaInsert.Clear();
if (i * 100 > lastRow)
break;
}
//SQL MERGE 2 tables
command = new SqlCommand("MERGE ORG AS TARGET"
+ " USING " + tempTable + " AS SOURCE"
+ " ON(TARGET.REFERENCJE = SOURCE.REFERENCJE)"
+ " WHEN MATCHED AND TARGET." + supplierName + " <> SOURCE.CENA THEN"
+ " UPDATE SET TARGET." + supplierName + " = SOURCE.CENA,"
+ " TARGET.PRODUCENT = SOURCE.PRODUCENT"
+ " WHEN NOT MATCHED BY TARGET THEN"
+ " INSERT(REFERENCJE, PRODUCENT, " + supplierName + ")"
+ " VALUES(SOURCE.REFERENCJE, SOURCE.PRODUCENT, SOURCE.CENA);", cs);
cs.Open();
command.ExecuteNonQuery();
cs.Close();
//DELETING temp table
command = new SqlCommand("DROP TABLE " + tempTable, cs);
cs.Open();
command.ExecuteNonQuery();
cs.Close();
//batchowanieInsert function
public void batchowanieInsert(DataTable tabela, string supplierName, string tempTable)
{
da.UpdateBatchSize = tabela.Rows.Count;
da.InsertCommand = new SqlCommand("INSERT INTO " + tempTable + " (REFERENCJE, PRODUCENT, CENA) VALUES (@REFERENCJE, @PRODUCENT, @CENA)", cs);
da.InsertCommand.Parameters.Add("@REFERENCJE", SqlDbType.VarChar, 20, "ref");
da.InsertCommand.Parameters.Add("@PRODUCENT", SqlDbType.VarChar, 20, "prod");
da.InsertCommand.Parameters.Add("@CENA", SqlDbType.VarChar, 20, "price");
da.InsertCommand.UpdatedRowSource = UpdateRowSource.None;
da.Update(tabela);
}
循环遍历单个 Excel 单元格总是会导致效率低下。我会建议:
将数据导入 SQL table 然后使用 SELECT 语句执行检查而不是 @ @ROWCOUNT(记住@@ROWCOUNT 是从服务器返回的消息,并针对您要插入的每一行传输到客户端)。使用@NOCOUN 来静音服务器回复。
或者考虑使用 CSV 而不是 Excel 工作簿。
将您的所有数据导入临时文件table(您可以使用多个 INSERT 语句,SqlServer 对大约 100 条记录的批处理性能更好)
更新存在的地方
在不存在的地方插入