首页 > 解决方案 > 从 C# 执行 SQL 命令的最快方法

问题描述

我正在为一个 SQL Server 数据库苦苦挣扎,我想在其中保留几个供应商的价格参考。

我正在读取.xlsx文件参考和价格,并将价格存储在 SQL Server 数据库中。我必须检查 ref 是否已经存在 - 如果是,我会更新,否则我需要插入。

一个 ref 大约需要 100-120 毫秒才能插入/更新到数据库中 - 大部分时间被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();

对不起我的英语不好。

问题解决了(当然感谢你们) 我建议 - 我决定创建临时表并将所有导入的数据放在那里。接下来将它与主表合并。此外,我将导入从.xlsx1 项更改为 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);
        }

标签: c#sqlexecutereader

解决方案


  1. 将所有数据导入临时表(您可以使用多条 INSERT 语句,SqlServer 在大约 100 条记录的批次中表现更好)

  2. 更新存在的地方

  3. 在不存在的地方插入


推荐阅读