【发布时间】: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