Asp.net 降低批量插入的执行速度

Asp.net 降低批量插入的执行速度,asp.net,sql-server,azure-sql-database,bulkinsert,Asp.net,Sql Server,Azure Sql Database,Bulkinsert,我们有一个位于S1定价层的Azure SQL数据库。我们的站点缓存量非常大,所以数据库访问量是绝对最小的。DTU的平均使用率仅为~1.5%,这是非常好的,因为我们的数据库成本仅为旧网站的一小部分(20英镑/米vs 400英镑/米!) 然而,在该网站上,我们确实有一些小脚本,需要插入大约100k条记录(当有人执行某个操作(如创建新教程)时,会发出用户通知) 触发时,DTU的峰值为100%,持续约3-5分钟 该脚本只是一个调用insert的循环: using(var db = new DBConte

我们有一个位于S1定价层的Azure SQL数据库。我们的站点缓存量非常大,所以数据库访问量是绝对最小的。DTU的平均使用率仅为~1.5%,这是非常好的,因为我们的数据库成本仅为旧网站的一小部分(20英镑/米vs 400英镑/米!)

然而,在该网站上,我们确实有一些小脚本,需要插入大约100k条记录(当有人执行某个操作(如创建新教程)时,会发出用户通知)

触发时,DTU的峰值为100%,持续约3-5分钟

该脚本只是一个调用insert的循环:

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
        );
    }
}
  • 有没有比这更快的插入方法
  • 另外,什么是最好的方法来降低这个脚本的执行速度,这样DTU的使用就不会阻塞所有的事情

不需要逐个实体插入,您可以同时插入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作业读取此信息,这允许您配置读取间隔,并像我之前写的那样插入数据库。
这种方法允许较大的负载(我在生产环境中有一些),如果代理或数据库出现问题,消息将存储在队列中,直到您将它们移动到数据库。

您每次插入一行-这是不高效的

A类似于反向数据读取器,效率很高

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());
    }
}
较低的技术是一次插入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());
    }
}

我很困惑。您想要一种更快的插入方式,但希望减慢执行速度?@Nkosi:Op希望查询不使用整个DTU。我不确定,如果您的查询并行运行,如果您的查询并行运行,您可能会使用更多资源。您可以尝试在插入期间将mdop更改为1,以查看您的DTU消耗是否降低
ALTER DATABASE SCOPED CONFIGURATION
也可以查看此答案:抱歉,为了澄清这一点,我想知道是否有一种方法可以提高插入性能,以及降低执行速度的最佳方法是确保并非所有DTU都被使用,我将使用表类型参数而不是JSON;至少它是强类型的。请参见此处:如果您使用强类型语言生成JSON,则没有问题。