2015-10-07 289 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();