【问题标题】:High CPU usage when SQL MERGE of 2,000 vehicles per secondSQL MERGE 每秒 2,000 辆车时 CPU 使用率高
【发布时间】:2016-07-02 09:49:25
【问题描述】:

这里有两个问题。

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();
   }
}

【问题讨论】:

  • 请检查执行计划重用...
  • 将所有行上传到数据库,然后一次合并所有行。
  • 你是否调用了这个脚本 2000 次?您应该创建一个 Type Userdefined 表。填充此类型并将其传递给存储过程。这样你只需要 1 次合并
  • 实际上,我们调用了超过 100 万条来自外部来源(而不是来自数据库本身)的记录。

标签: sql-server merge sql-server-2012 sql-server-2014


【解决方案1】:

创建单个存储过程:

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

并从您的代码中执行此 SP。

【讨论】:

  • 仅供参考 - 不是我让你的答案被否决。忙于几个项目,所以我会尽快回复这篇文章。
  • 这当然有帮助。它几乎减少了一半的时间,而 Window 的任务管理器上的 CPU 使用率保持在 10% 以下。关于进一步加快速度的任何建议?我每 4 秒处理 5,000 辆汽车,那么每秒可以处理 10,000 辆汽车吗?谢谢。
猜你喜欢
  • 2019-01-13
  • 2020-10-08
  • 2023-04-03
  • 1970-01-01
  • 1970-01-01
  • 2014-03-14
  • 1970-01-01
  • 1970-01-01
  • 2021-12-09
相关资源
最近更新 更多