2016-03-16 55 views
0

這裏有兩個問題。每秒2,000輛車的SQL MERGE時CPU使用率高

1)有誰知道爲什麼當每秒合併2,000輛車時,CPU佔用率過高?

2)好奇,是否有一種方法可以在沒有高CPU使用率的情況下每秒合併10,000輛車?

//Table & Index syntax... 
CREATE TABLE [dbo].[Dealer_SalesVehicles](
    [RawID] [bigint] IDENTITY(1,1) NOT NULL, 
    [AccountID] [bigint] NOT NULL, 
    [StockNumber] [nvarchar](50) NOT NULL, 
    [Vin] [nvarchar](30) NOT NULL, 
    [Year] [nvarchar](50) NOT NULL, 
    [Make] [nvarchar](50) NOT NULL, 
    [Model] [nvarchar](50) NOT NULL, 
    [Style] [nvarchar](80) NOT NULL 
CONSTRAINT [PK_Dealer_SalesVehicles_AccountId_StockNumber_Vin] PRIMARY KEY CLUSTERED 
(
    [AccountID] ASC, 
    [StockNumber] ASC, 
    [Vin] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 100) ON [PRIMARY] 
) ON [PRIMARY] 

//Sql Query... 
var sqlAsk = ""; 
var rowAffected = 0; 
var errorSqlParameters = new List<Tuple<string, string>>(); ; 

using (var dbConnection = new SqlConnection(this._databaseConnectionString)) 
{ 
    using (var dbCommand = dbConnection.CreateCommand()) 
    { 
     sqlAsk = ""; 
     sqlAsk += " MERGE "; 
     sqlAsk += "  TOP (1)[dbo].[Dealer_SalesVehicles] WITH(HOLDLOCK) AS t "; 
     sqlAsk += "  USING "; 
     sqlAsk += "   (SELECT "; 
     sqlAsk += "    @parmAccountId, @parmStockNumber, @parmVin "; 
     sqlAsk += "  ) "; 
     sqlAsk += "   AS s "; 
     sqlAsk += "   ("; 
     sqlAsk += "    [AccountID], [StockNumber], [VIN] "; 
     sqlAsk += "  ) "; 
     sqlAsk += "  ON(t.[AccountId] = s.[AccountId] AND t.[StockNumber] = s.[StockNumber] AND t.[Vin] = s.[Vin]) "; 
     //#-- if matched, update existing record if right conditions are met(see Description in header)... 
     sqlAsk += " WHEN MATCHED AND(t.[AccountId] = s.[AccountId]) AND t.[StockNumber] = s.[StockNumber] AND(t.[Vin] = s.[Vin]) THEN "; 
     sqlAsk += "  UPDATE SET "; 
     //AccountID... 
     //StockNumber... 
     //VIN... 
     sqlAsk += "   t.[Year] = @parmYear, "; 
     sqlAsk += "   t.[Make] = @parmMake, "; 
     sqlAsk += "   t.[Model] = @parmModel, "; 
     sqlAsk += "   t.[Style] = @parmStyle "; 
     //#-- if not matched, add new record and set return values... 
     sqlAsk += " WHEN NOT MATCHED THEN "; 
     //#--http://stackoverflow.com/questions/1609208/need-help-with-the-merge-statement... 
     //#--(Cannot use "s." or "t." here, for source or target table - name - abbreviation cuz "Columns name in the insert list can only refer to the target table, so the parser doesn't expect to see a table alias there, wouldn't know how to resolve it. It sees "column1", it knows it belongs to the target table. It sees "table1.column1", it doesn't know what "table1" means. "table1" is out of scope, so to speak")... 
     sqlAsk += "  INSERT("; 
     //RawID... 
     sqlAsk += "   [AccountID], [StockNumber], [VIN], "; 
     sqlAsk += "   [Year], [Make], [Model], [Style] "; 
     sqlAsk += " ) "; 
     sqlAsk += "  VALUES("; 
     sqlAsk += "   @parmAccountId, @parmStockNumber, @parmVin, "; 
     sqlAsk += "   @parmYear, @parmMake, @parmModel, @parmStyle "; 
     sqlAsk += " ) "; 
     sqlAsk += " ; "; //#--required semicolon separator for MERGE.... 

     dbCommand.CommandTimeout = 60; 
     dbCommand.CommandText = sqlAsk; 
     dbCommand.Parameters.Clear(); 
     dbCommand.Parameters.Add(new SqlParameter("@parmAccountId", SqlDbType.BigInt)).Value = parmSqlSalesVehicleRequest.DealerBranchAccountId; 
     dbCommand.Parameters.Add(new SqlParameter("@parmStockNumber", SqlDbType.NVarChar)).Value = parmSqlSalesVehicleRequest.StockNumber; 
     dbCommand.Parameters.Add(new SqlParameter("@parmVin", SqlDbType.NVarChar)).Value = parmSqlSalesVehicleRequest.Vin; 
     dbCommand.Parameters.Add(new SqlParameter("@parmYear", SqlDbType.NVarChar)).Value = parmSqlSalesVehicleRequest.Year; 
     dbCommand.Parameters.Add(new SqlParameter("@parmMake", SqlDbType.NVarChar)).Value = parmSqlSalesVehicleRequest.Make; 
     dbCommand.Parameters.Add(new SqlParameter("@parmModel", SqlDbType.NVarChar)).Value = parmSqlSalesVehicleRequest.Model; 
     dbCommand.Parameters.Add(new SqlParameter("@parmStyle", SqlDbType.NVarChar)).Value = parmSqlSalesVehicleRequest.Style; 

     foreach (SqlParameter sqlParameter in dbCommand.Parameters) 
     { 
      errorSqlParameters.Add(new Tuple<string, string>(sqlParameter.ParameterName, sqlParameter.Value.ToString())); 
     } 

     if (dbConnection.State == ConnectionState.Open) { dbConnection.Close(); } 

     await dbConnection.OpenAsync(); 

     rowAffected = await dbCommand.ExecuteNonQueryAsync(); 
    } 
} 
+0

請檢查執行計劃重用... – Devart

+0

將所有行上傳到db,然後一次對所有行進行合併。 –

+0

你是否在調用這個腳本2000次?您應該創建一個Type Userdefined表。填充此類型並將其傳遞給存儲過程。這樣你只需要1次合併 –

回答

0

創建一個存儲過程:

CREATE PROCEDURE dbo.usp_Add 
(
    @parmAccountId ..., 
    @parmStockNumber 
) 
AS BEGIN 

    SET NOCOUNT ON; 

    MERGE TOP(1) dbo.Dealer_SalesVehicles WITH (HOLDLOCK) t 
    USING (
     SELECT [AccountID] = @parmAccountId, 
       [StockNumber] = @parmStockNumber, 
       [VIN] = @parmVin 
    ) s ON t.[AccountId] = s.[AccountId] 
     AND t.[StockNumber] = s.[StockNumber] 
     AND t.[Vin] = s.[Vin] 
    WHEN MATCHED 
     THEN UPDATE 
      SET 
       t.[year] = @parmYear, 
       t.[Make] = @parmMake, 
       t.[model] = @parmModel, 
       t.[style] = @parmStyle 
    WHEN NOT MATCHED 
     THEN INSERT ([AccountID], [StockNumber], [VIN], [year], [Make], [model], [style]) 
     VALUES (@parmAccountId, @parmStockNumber, @parmVin, @parmYear, @parmMake, @parmModel, @parmStyle); 

END 
GO 

從你的代碼Exec的這一SP。

+0

請告訴...怎麼了? – Devart

+0

僅供參考 - 這不是我的投票答案。一直忙於幾個項目,所以我會盡我所能回到這篇文章。 – fletchsod

+0

這當然有幫助。 Window的任務管理器CPU使用率保持在10%以下的時間幾乎減少了一半。任何有關加速進一步的建議?我每4秒處理5000輛車,那麼每秒能做10,000輛車嗎?謝謝。 – fletchsod