更新SQL表非常慢

时间:2017-03-24 07:19:03

标签: sql performance insert

我尝试使用更新SQL表时遇到问题 我有datagridview,我需要更新SQL表并从值datagridview获取值。我的datagridview有超过10000行 我花时间超过1:30非常慢

datagridview名称“dgv_balance”

以下是代码:

using (SqlConnection cn = new SqlConnection())
{
    cn.ConnectionString = "My Connection"
    cn.Open();
    using (SqlCommand cmd_select = new SqlCommand())
    {
        for (int i = 0; i < dgv_balance.RowCount; i++)
        {
            cmd_select.Connection = cn;
            cmd_select.CommandType = CommandType.StoredProcedure;
            cmd_select.CommandText = "clients_balances_select_glid_date";
            cmd_select.Parameters.AddWithValue("@glid", Convert.ToString(dgv_balance.Rows[i].Cells[0].Value));
            cmd_select.Parameters.AddWithValue("@date", Convert.ToDateTime(dgv_balance.Rows[i].Cells[2].Value));
            if (cmd_select.ExecuteScalar().ToString()=="")
            {
                using (SqlCommand cmd_insert = new SqlCommand())
                {
                    cmd_insert.Connection = cn;
                    cmd_insert.CommandType = CommandType.StoredProcedure;
                    cmd_insert.CommandText = "clients_balances_insert_data";
                    cmd_insert.Parameters.AddWithValue("@glid", Convert.ToString(dgv_balance.Rows[i].Cells[0].Value));
                    cmd_insert.Parameters.AddWithValue("@name", Convert.ToString(dgv_balance.Rows[i].Cells[1].Value));
                    cmd_insert.Parameters.AddWithValue("@date", Convert.ToString(dgv_balance.Rows[i].Cells[2].Value));
                    cmd_insert.Parameters.AddWithValue("@balance", Convert.ToString(dgv_balance.Rows[i].Cells[3].Value));
                    cmd_insert.ExecuteNonQuery();
                    cmd_insert.Parameters.Clear();
                }
            }
            else
            {
                using (SqlCommand cmd_update= new SqlCommand())
                {
                    cmd_update.Connection = cn;
                    cmd_update.CommandType = CommandType.StoredProcedure;
                    cmd_update.CommandText = "clients_balances_update_balance";
                    cmd_update.Parameters.AddWithValue("@glid", Convert.ToString(dgv_balance.Rows[i].Cells[0].Value));
                    cmd_update.Parameters.AddWithValue("@date", Convert.ToString(dgv_balance.Rows[i].Cells[2].Value));
                    cmd_update.Parameters.AddWithValue("@balance", Convert.ToString(dgv_balance.Rows[i].Cells[3].Value));
                    cmd_update.ExecuteNonQuery();
                    cmd_update.Parameters.Clear();
                }
            }
            cmd_select.Parameters.Clear();
        }
    }
}

2 个答案:

答案 0 :(得分:1)

在遍历datagridview行并缓存结果数据并在迭代datagridview时检查结果而不是在每行上调用结果数据之前,可能只需要调用SELECT命令一次。这样您就可以将命令减少10000。 如果您能向我们展示您的程序查询,也会更好。 或者,如果您的datagridview是数据的 ONLY 来源,那么您可以删除数据库中以前的所有数据,并为所有datagridview数据进行一次插入调用。

试试这个:

using (SqlConnection cn = new SqlConnection())
{
 cn.ConnectionString = "MyConnection" ;
 cn.Open();
 SqlDataAdapter da = new SqlDataAdapter(); 
 DataTable dt = new DataTable();
 using (SqlCommand cmd_select = new SqlCommand()) 
 {
   cmd_select.Connection = cn;      cmd_select.CommandType =   CommandType.StoredProcedure;    cmd_select.CommandText =   "clients_balances_select_glid_date";
  da.SelectCommand = cmd_select; 
  da.Fill(dt);
  for (int i = 0; i < dgv_balance.RowCount; i++) 
  { 
    if(/* check here if dt contains this    row*/)
    {
        // Insert
    }
    else 
    {
        // Update
     }
   }
 }
}

答案 1 :(得分:1)

我认为您应该一次插入或更新所有数据。

  1. 为glId列创建索引。如果glId是主键,则将其编入索引。

  2. 假设List ClientBalance是您需要更新或插入的列表项。

    public class ClientBalance
    {
       GlId int {get;set;}
       ClientName string {get;set;}
       Balance decimal {get;set;}
       DateInput DateTime {get;set;}
    }
    
  3. 您可以将列表项序列化为xml字符串并将其传递给存储过程

       public  string Serialize<T>(T value) where T : new()
        {
            var serializeXml = string.Empty;            
            if (value != null)
            {
                try
                {
                    var xmlserializer = new XmlSerializer(typeof(T));
                    var stringWriter = new StringWriter();
                    var writer = XmlWriter.Create(stringWriter);
                    xmlserializer.Serialize(writer, value);
                    serializeXml = stringWriter.ToString();
    
                    writer.Close();
                }
                catch (Exception ex)
                {                   
                    return string.Empty;
                }
            }
            return serializeXml;
        }
    
    1. 为插入或更新项目创建一个新的存储过程:

          CREATE PROCEDURE [dbo].[clients_balances_insert_or_update]
           (
              @xmlObject nvarchar(max)
           )
           AS
           BEGIN
                -- TABLE INCLUDE DATE FROM XML
              DECLARE @tblBalances AS TABLE
              (
                 GlId int,
                 DateInput datetime,
                 ClientName nvarchar(50),
                 Balance decimal(18,2)
              )
              DECLARE @idoc int -- xml id
      
               -- PARSE XML TO OBJECT
              EXEC sp_xml_preparedocument @idoc OUTPUT, @xmlObject 
              INSERT INTO @tblBalances
                              (
                                  GlId, DateInput, ClientName, Balance
                              )
                              SELECT s.GlId, s.DateInput, s.ClientName, s.Balance
                              FROM    OPENXML (@idoc, '/ArrayOfClientBalance/ClientBalance', 8) WITH (
                                          GlId            int 'GlId',                     
                                          DateInput   datetime 'DateInput',
                                          ClientName NVARCHAR(50) 'ClientName',
                                          Balance DECIMAL(18,2) 'Balance'
                                      ) s
              EXEC sp_xml_removedocument @idoc
      
              -- USE MERGE FOR INSERT OR UPDATE DATE
              -- Use transaction 
              BEGIN TRAN InsertOrUpdate
              BEGIN TRY
                  MERGE Target AS T
                  USING @tblBalances AS S
                  ON (T.GlId = S.GlId) 
                  WHEN NOT MATCHED BY TARGET 
                     THEN INSERT( GlId, DateInput, ClientName, Balance) VALUES( GlId, DateInput, ClientName, Balance)
                  WHEN MATCHED 
                     THEN UPDATE SET DateInput = S.DateInput, Balance = s.Balance
      
                  COMMIT TRAN InsertOrUpdate;
              END TRY
              BEGIN CATCH
                  ROLLBACK TRAN InsertOrUpdate;
                  THROW;
              END CATCH
           END  
      
    2. 希望这有用!