我想知道我们的应用程序是否已经获得了最快的 SqlSever 写入性能。
我们创建了一个示例应用程序,它对本地 SQL Server 数据库执行 BulkCopy 操作。 BulkCopy 操作从内存中的 DataTable 写入 100,000 行数据。插入的表没有索引。这是因为我们只想获得SQL Server的最大写入速度。
这是我们要插入的表的架构:
CREATE TABLE [dbo].[HistorySampleValues](
[HistoryParameterID] [bigint] NOT NULL,
[SourceTimeStamp] [datetime2](7) NOT NULL,
[ArchiveTimestamp] [datetime2](7) NOT NULL,
[ValueStatus] [int] NOT NULL,
[ArchiveStatus] [int] NOT NULL,
[IntegerValue] [int] SPARSE NULL,
[DoubleValue] [float] SPARSE NULL,
[StringValue] [varchar](100) SPARSE NULL,
[EnumNamedSetName] [varchar](100) SPARSE NULL,
[EnumNumericValue] [int] SPARSE NULL,
[EnumTextualValue] [varchar](256) SPARSE NULL
) ON [PRIMARY]
我们通过 C# 代码衡量性能。
public double PerformBulkCopy()
{
DateTime timeToBulkCopy = DateTime.Now;
double bulkCopyTimeSpentMs = -1.0;
DataTable historySampleValuesDataTable = CreateBulkCopyRecords();
//start the timer here
timeToBulkCopy = DateTime.Now;
using (SqlConnection sqlConn = ConnectDatabase())
{
sqlConn.Open();
using (SqlTransaction sqlTransaction = sqlConn.BeginTransaction())
{
try
{
using (SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(sqlConn, SqlBulkCopyOptions.KeepIdentity, sqlTransaction))
{
sqlBulkCopy.ColumnMappings.Add(SqlServerDatabaseStrings.SQL_FIELD_HISTORY_PARMETER_ID, SqlServerDatabaseStrings.SQL_FIELD_HISTORY_PARMETER_ID);
sqlBulkCopy.ColumnMappings.Add(SqlServerDatabaseStrings.SQL_FIELD_SOURCE_TIMESTAMP, SqlServerDatabaseStrings.SQL_FIELD_SOURCE_TIMESTAMP);
sqlBulkCopy.ColumnMappings.Add(SqlServerDatabaseStrings.SQL_FIELD_VALUE_STATUS, SqlServerDatabaseStrings.SQL_FIELD_VALUE_STATUS);
sqlBulkCopy.ColumnMappings.Add(SqlServerDatabaseStrings.SQL_FIELD_ARCHIVE_STATUS, SqlServerDatabaseStrings.SQL_FIELD_ARCHIVE_STATUS);
sqlBulkCopy.ColumnMappings.Add(SqlServerDatabaseStrings.SQL_FIELD_INTEGER_VALUE, SqlServerDatabaseStrings.SQL_FIELD_INTEGER_VALUE);
sqlBulkCopy.ColumnMappings.Add(SqlServerDatabaseStrings.SQL_FIELD_DOUBLE_VALUE, SqlServerDatabaseStrings.SQL_FIELD_DOUBLE_VALUE);
sqlBulkCopy.ColumnMappings.Add(SqlServerDatabaseStrings.SQL_FIELD_STRING_VALUE, SqlServerDatabaseStrings.SQL_FIELD_STRING_VALUE);
sqlBulkCopy.ColumnMappings.Add(SqlServerDatabaseStrings.SQL_FIELD_ENUM_NAMEDSET_NAME, SqlServerDatabaseStrings.SQL_FIELD_ENUM_NAMEDSET_NAME);
sqlBulkCopy.ColumnMappings.Add(SqlServerDatabaseStrings.SQL_FIELD_ENUM_NUMERIC_VALUE, SqlServerDatabaseStrings.SQL_FIELD_ENUM_NUMERIC_VALUE);
sqlBulkCopy.ColumnMappings.Add(SqlServerDatabaseStrings.SQL_FIELD_ENUM_TEXTUAL_VALUE, SqlServerDatabaseStrings.SQL_FIELD_ENUM_TEXTUAL_VALUE);
sqlBulkCopy.DestinationTableName = SqlServerDatabaseStrings.SQL_TABLE_HISTORYSAMPLEVALUES;
sqlBulkCopy.WriteToServer(historySampleValuesDataTable);
}
sqlTransaction.Commit();
//end the timer here
bulkCopyTimeSpentMs = DateTime.Now.Subtract(timeToBulkCopy).TotalMilliseconds;
}
catch (Exception ex)
{
sqlTransaction.Rollback();
}
CleanUpDatabase(sqlConn);
}
sqlConn.Close();
}
return bulkCopyTimeSpentMs;
}
我尝试了 SqlBulkCopy.WriteToServer() 的不同重载:DataTable、DataReader 和 DataRow[]。
在具有此规范的机器上: I3-2120 CPU @ 3.30GHz 8GB 内存 希捷酷鱼 7200.12 ST3500413AS 500GB 7200 转
我使用不同的重载获得每秒插入 ~150K-160K 行的吞吐量。
顺便说一句,我没有在测量中包括 DataTable 的创建,因为我只是想获得 SQLBulkCopy 的实际性能作为基准。
我现在要问,给定我们的示例数据和示例表,这是我们可以从 SQL Server SE 中获得的最多吗?或者我们可以做些什么来加快速度?
如果您需要有关我们设置的更多信息,请告诉我
最佳答案
SSIS 和 bcp 实用程序的性能会更好。
如果您必须使用 SqlBulkCopy,请确保您已经掌握了所有基础知识:禁用索引和触发器、切换到简单或批量加载恢复模型以最小化 tlog、表上的 x-lock 等等。还要微调 BatchSize 属性(取决于您的数据,它可能是 100 到 5000 之间的值),也许还有 UseInternalTransaction。
这是您可能会发现有用的 MSDN 链接:
关于获得最大 SQL Server 2012 写入性能的 C# 代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23212333/