背景:许多(数百个)远程资产通过 UDP 数据包从多个数据系统将数据发送到一个域,在该域中数据包被解析并加载到
System.Data.DataTable
中。每个数据点都是一个单独的System.Data.DataRow
。
平均每天我们有 29 亿个数据点。所以有很多数据。有一个“实时”表,仅包含最新版本的数据。该表被分区为远程资产和数据系统上的不同数据库文件。
此外,远程资产分布在多台 SQL Server 计算机之间。通过表死锁进一步分散数据库和 UDP 到达问题。
一旦到达数据被解析并加载到 C# 中,
DataTable
,该远程资产/数据系统的现有数据将被删除,并且 BulkCopy
用于插入 C# 数据表中的行。这可行,但是?
我的问题:有没有办法更新而不是暴力删除/插入?我查看了链接 Using SQLBuilCopy to Insert Data 和 C# Bulk Insert... 但我现在几乎正在做一个临时表。
如果我每次都创建一个
#temp
表,那么就会产生开销。然后我还是要把数据取到实时表中,然后删除#temp
表。
我查看了
SqlDataAdapter
,但这更多的是为了更新现有数据,而且可能是少量的。
任何想法都会有帮助。
其他背景:我可以看到 SQL Server 的性能随着时间的推移而下降,尽管这应该是一个问题。另外,我必须经常对表进行重新分区,因为性能下降得很厉害(8 小时内出现 10,000 次超时或死锁等)。
您可能会考虑一种更复杂的方法,包括使用临时表与 MERGE 语句相结合来更新实时表。 MERGE 语句可以在单个操作中处理插入和更新,这针对高性能进行了优化,并避免了连续创建和删除临时表的开销。
您可以尝试以下方法:
这是 SQL 中的示例合并语句:
string mergeSql = @"
MERGE INTO RealTimeTable AS target
USING StagingTable AS source
ON (target.AssetId = source.AssetId AND target.DataSystemId = source.DataSystemId AND target.Timestamp = source.Timestamp)
WHEN MATCHED THEN
UPDATE SET
target.DataPointValue = source.DataPointValue,
-- other column updates
WHEN NOT MATCHED BY TARGET THEN
INSERT (
AssetId,
DataSystemId,
DataPointValue,
Timestamp
-- other columns
) VALUES (
source.AssetId,
source.DataSystemId,
source.DataPointValue,
source.Timestamp
-- other columns
)
WHEN NOT MATCHED BY SOURCE THEN
DELETE;
TRUNCATE TABLE StagingTable; -- Clear the staging table after processing
";
using (SqlCommand mergeCommand = new SqlCommand(mergeSql, connection))
{
mergeCommand.ExecuteNonQuery();
}