2015-10-07 290 views
1

我正在处理一些更新UCommerce中的项目的代码(而不是我自己的代码)。这段代码更新UDF的产品。我遇到了执行速度的问题。通过foreach循环的每次迭代得到的速度都比以前慢。当执行开始时,它每秒循环5-6次,但是到它处理了500次迭代时,它已经每5-6秒减慢一次,现在是910个项目,并且每10-11秒减慢到1。如代码所示,在提交事务和刷新会话之前,它正在处理200(_batchsize)项。处理foreach循环的执行时间过长

内存,CPU和磁盘IO都很好看。没有过多的CPU使用率,大量的可用内存和磁盘瓶颈。运行应用程序时,内存使用量保持稳定在350Mb左右。

我看到了同样的问题,无论是从IDE还是编译的exe运行它。

我已经尝试减少批量大小,我也尝试提交事务和冲洗每个项目的会话,但它使得非常小的差异。我只是想知道是否有人可以提出任何我可以尝试甚至识别可能存在问题的地方。

public class ccProductUDFs 
{ 
    public string ProductName { get; set; } 
    public string FieldName { get; set; } 
    public string DataType { get; set; } 
    public string DisplayName { get; set; } 
    public string SKU { get; set; } 
    public bool Facet { get; set; } 
    public bool Searchable { get; set; } 
    public bool RenderInEditor { get; set; } 
    public string DefinitionName { get; set; } 
    public string DefinitionDescription { get; set; } 
    public string UdfValue { get; set; } 
    public bool UdfValueHasChanged { get; set; } 
    public bool UdfFieldHasChanged { get; set; } 
    public bool UdfFieldDeleted { get; set; } 
    public bool DisplayOnSite { get; set; } 
    public string CultureCode { get; set; } 

    public override string ToString() 
    { 
     return string.Format("{0} {1} : {2} = {3}", this.SKU, this.ProductName, this.DisplayName, this.UdfValue); 
    } 
} 

//This will load approx. 173000 item for a SQL database 
List<ccProductUDFs> listudfs = ccProductUDFsData.Load(DBConfiguration.GetDBContext()); 
//_batchsize is set to 200 

//processUdFs is a Boolean = true stored in AppSettings 

    #region Update any UDFs... 

    _startrange = 0; 
    started = DateTime.Now; 
    timeTaken = TimeSpan.MinValue; 
    timeLeft = TimeSpan.MinValue; 
    doneCount = 0; 
    _totalCount = listudfs.Count(); 
    while (_processUdFs && _startrange < listudfs.Count()) 
    { 
     int sz = listudfs.Count() - _startrange >= _batchsize ? _batchsize : listudfs.Count() - _startrange; 
     List<ccProductUDFs> shallowlist = listudfs.GetRange(_startrange, sz); 
     _startrange = _startrange + sz; 

      _session = SessionContext.Session; 
      // create a response list to hold results of uploads... 
      List<ccResponse> response_categoryUDFs = new List<ccResponse>(); 

      // start the transaction 
      using (var tx = _session.BeginTransaction()) 
      { 
       _dbcontext.BeginTransaction(); 
       int counter = 0; 
       int listcount = listudfs.Count(); 

       // loop through each remaining UDF 
       // these are UDFs where the FIELD or the VALUE has changed, and we have not dealt with it as part of the product 
       foreach (ccProductUDFs udf in shallowlist) 
       { 
        if (ShowLog(verbose, (_startrange - sz) + ++counter, listcount)) 
        { 
         TimeSpan elapsed = (DateTime.Now - started); 
         WriteLogV2("product udfs {0} of {1}", (_startrange - sz) + counter, listcount, elapsed); 


        } 
        // get the product for this UDF... 
        var product = _session.Query<Product>().FirstOrDefault(a => a.Sku == udf.SKU); 


        if (product != null) 
        { 
         // check that product has a product definition... 
         if (product.ProductDefinition == null) 
         { 
          // product has no definition assigned, so check that the product definition exists in data... 
          ProductDefinition definition = _session.Query<ProductDefinition>().FirstOrDefault(a => a.Description == udf.DefinitionName); 
          if (definition == null) 
          { 
           // product definition doesn;t exist in data, so create it... 
           definition = new ProductDefinition(); 
           definition.Description = udf.DefinitionDescription; 
           definition.Name = udf.DefinitionName; 

           // save the changes... 
           _session.SaveOrUpdate((ProductDefinition)definition); 


          } 

          // assign this product definition to the product record... 
          product.ProductDefinition = definition; 
         } 

         // determine if the UDF FIELD exists... 
         ProductDefinitionField definitionfield = product.ProductDefinition.ProductDefinitionFields.FirstOrDefault(a => a.Name == udf.FieldName); 
         if (definitionfield == null) 
         { 
          // the UDF FIELD does NOT exist, so we shall add it. 
          definitionfield = new ProductDefinitionField(); 
          definitionfield.Name = udf.FieldName; 
          definitionfield.ProductDefinition = product.ProductDefinition; 

          // locate the data type record and assign it to this UDF FIELD 
          var dt = _session.Query<DataType>().FirstOrDefault(a => a.TypeName == udf.DataType); 
          if (dt != null) 
          { 
           definitionfield.DataType = dt; 
          } 

          // add the UDF FIELD to the product category... 
          product.ProductDefinition.ProductDefinitionFields.Add(definitionfield); 

          // save the changes... 
          _session.SaveOrUpdate((Product)product); 

         } 

         bool changed = definitionfield.Deleted != udf.UdfFieldDeleted; 

         // assign properties to this UDF FIELD... 
         definitionfield.Deleted = udf.UdfFieldDeleted; 

         if (changed) 
         { 
          // save the changes... 
          _session.SaveOrUpdate((ProductDefinitionField)definitionfield); 
         } 

         // determine if the UDF VALUE record exists... 
         ProductProperty property = product.ProductProperties.FirstOrDefault(a => a.ProductDefinitionField.Name == definitionfield.Name && a.Product.Id == product.ProductId); 
         if (property == null) 
         { 
          // the UDF VALUE does NOT exist, so we shall add it. 
          property = new ProductProperty(); 
          property.ProductDefinitionField = definitionfield; 
          property.Product = product; 

          // add the UDF VALUE to the product category... 
          product.ProductProperties.Add(property); 
         } 

         changed = false; 

         string v = udf.UdfValue == null ? string.Empty : udf.UdfValue.Trim(); 

         changed = property.Value != v; 

         // assign properties to this UDF FIELD... 
         property.Value = v; 

         if (changed) 
         { 
          // save the changes... 
          _session.SaveOrUpdate((ProductProperty)property); 

          // save the changes... 
          _session.SaveOrUpdate((Product)product); 
         } 

         // update the response with a successful result... 
         response_categoryUDFs.Add(new ccResponse(udf.SKU, udf.FieldName, ccCategoryUDFsData.Source, true, "", 0)); 
        } 
        object[] prodparam = 
           { 
            _dbcontext.NewParameter("@Sku", udf.SKU), 
            _dbcontext.NewParameter("@udfName", udf.FieldName) 
           }; 
        _dbcontext.ExecuteNonQuery(CommandType.Text, 
         "UPDATE [LOAD_ProductUdfValues] SET HasChanged = 0 WHERE ProductId = @Sku And FieldName = @udfName", 
         prodparam); 

        TimeSpan ts = DateTime.Now - started; 
        doneCount++; 
        Console.WriteLine("Done {0} of {1} in {2}", doneCount, _totalCount, ts.ToString(@"hh\:mm\:ss")); 
       } 

       try 
       { 
        // commit all changes... 
        tx.Commit(); 
        _dbcontext.CommitTransaction(); 
       } 
       catch (Exception ex) 
       { 
        // Error Handler 
        tx.Rollback(); 
        _dbcontext.RollbackTransaction(); 
        response_categoryUDFs.Clear(); 
        response_categoryUDFs.Add(new ccResponse("", "", ccCatalogData.Source, false, "Commit failed [" + ex.ToString() + "]", 1)); 
       } 
      } 

      // send any response... 
      ccResponse.Write(_dbcontext, response_categoryUDFs, ccCatalogData.ResponseTarget); 

      // tidy up the session before is it disposed... 
      _session.Flush(); 
     // } 
    } 
    #endregion 
+0

不熟悉'SessionContext'但如果之后增加_session.Clear();固定我的问题'SaveOrUpdate'就像'DataTable' CRUD什么然后哎哟。在一种情况下,我们抛弃了存储过程中的“DataTable”处理。处理时间从24小时变为5秒。我没有骗你。 – radarbob

+0

它看起来像你没有使用uCommerce API。它是实体框架,Linq2Sql还是....? – lasseeskildsen

+0

不,它是UCommerce API。我已经与UCommerce交谈过,结果发现这种行为是他们期望在如此大规模的数据推送上。他们用户NHibernate和这是造成这个问题。他们还提供无状态会话API,这对于批量插入和更新来说要好得多。 – Fred

回答

0

如果任何人发现这在搜索我已经只是_session.Flush();