我们有一个Azure SQL数据库,它位于S1定价层。我们的网站被高度缓存,因此数据库命中率极低。平均DTU使用率仅为1.5%,这很好,因为我们的数据库成本只是旧网站的一小部分(20英镑/米对400英镑/米!)
但是,在网站上,我们确实有一些小脚本需要插入~100k左右的记录(当有人执行某项操作时会发出用户通知,例如创建新教程)。
当触发此操作时,DTU飙升至100%约3-5分钟。
脚本只是一个调用插入的循环:
using(var db = new DBContext())
{
foreach(var userID in userIDs)
{
db.ExecuteCommand(
"INSERT INTO UserNotifications " +
"(ForUserID, Date, ForObjectTypeID, ForObjectID, TypeID, Count, MetaData1)
VALUES ({0}, {1}, NULL, {2}, {3}, {4}, {5}, {6})",
userID, DateTime.Now.ToUniversalTime(), forObjectID, (byte)type, 1, metaData1.Value
);
}
}
答案 0 :(得分:2)
您每次插入一行 - 这效率不高。
TVP类似于反向数据加载器,效率很高。
低技术是一次插入900行(1000是最大值)。仅此一项效率可能提高400倍。
StringBuilder sb = new StringBuilder();
string insert = "INSERT INTO UserNotifications " +
"(ForUserID, Date, ForObjectTypeID, ForObjectID, TypeID, Count, MetaData1) " +
"VALUES ";
sb.AppendLine(insert);
int count = 0;
using(var db = new DBContext())
{
foreach(var userID in userIDs)
{
sb.AppendLine(string.Format(({0}, {1}, NULL, {2}, {3}, {4}, {5}, {6}), ",
userID, DateTime.Now.ToUniversalTime(), forObjectID, (byte)type, 1, metaData1.Value);
count++;
if (count = 990)
{
db.ExecuteCommand(sb.ToString());
count = 0;
sb.Clear();
sb.AppendLine(insert);
//can sleep here to throttle down cpu
}
}
if (count > 0)
{
db.ExecuteCommand(sb.ToString());
}
}
答案 1 :(得分:0)
不是逐个实体插入,而是可以插入100个实体,同时将实体打包在JSON中,并编写使用它的存储过程,如下例所示:
INSERT INTO [dbo].[AISecurityLogs]
([IpAddress], [TimeRange], [Requests], [LogId])
SELECT *, LogId = @logId
FROM OPENJSON ( @json )
WITH (
IpAddress varchar(15) '$.IpAddress',
TimeRange DATETIME '$.TimeRange',
Requests int '$.Requests'
)
要减慢执行速度并且不丢失任何内容,您可以将日志放入队列中,然后使用azure作业读取此信息,这样可以配置读取间隔,并在数据库中插入之前写过。 这种方法允许大负载(我在生产环境中有几个),如果代理或数据库出现问题,消息将存储在队列中,直到您将它们移动到数据库。