Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# ASP.NET核心web应用中ADO.NET大数据检索的性能_C#_Sql Server_Asp.net Core_Ado.net - Fatal编程技术网

C# ASP.NET核心web应用中ADO.NET大数据检索的性能

C# ASP.NET核心web应用中ADO.NET大数据检索的性能,c#,sql-server,asp.net-core,ado.net,C#,Sql Server,Asp.net Core,Ado.net,应用程序是用编写的.NET Core 2.1和数据库是SQL Server 2014 有一个页面必须从SQL Server检索8万到10万行数据。我已经为我认为合适的列添加了索引,查询可以在大约5秒钟内返回所有行。因此,由于应用程序必须迭代所有这些行并创建视图模型对象,因此需要另外6-8秒来循环并执行所有必要的逻辑。这导致总加载时间约为16-17秒 在任何人建议使用分页之前,这个视图被设计成一个Excel工作表,并通过一系列CSS有趣的操作使它看起来更美观。由于我在后端找不到任何更多的循环优化,

应用程序是用编写的.NET Core 2.1数据库SQL Server 2014

有一个页面必须从SQL Server检索8万到10万行数据。我已经为我认为合适的列添加了索引,查询可以在大约5秒钟内返回所有行。因此,由于应用程序必须迭代所有这些行并创建视图模型对象,因此需要另外6-8秒来循环并执行所有必要的逻辑。这导致总加载时间约为16-17秒

在任何人建议使用分页之前,这个视图被设计成一个Excel工作表,并通过一系列CSS有趣的操作使它看起来更美观。由于我在后端找不到任何更多的循环优化,并且我已经压缩了通过IIS Compress Dynamic选项返回的视图,所以我认为唯一可以节省一些时间的方法是批量查询数据库。我测试了一次执行10000个批处理的运行,结果在不到1秒的时间内返回到SQL管理中。因此,我编写了一些代码来启动一个
任务
,该任务创建了自己的数据库连接,并对其10000条记录进行了查询,然后在一个循环中执行此操作,创建足够的任务来覆盖需要返回的记录量。这适用于上一个查询,该查询返回给定记录范围的最小和最大标识值,该范围不在付款期的日期范围内。然后,我对每个任务执行一个
wait任务。WhenAll()
,认为这样可以缩短从SQL中最初提取数据时的等待时间。我发现这会导致几乎相同甚至更糟的等待时间

在这一点上,我对如何提高绩效没有任何想法,希望有人能提出另一个想法。我将提供我的
任务
方法来调用数据库以获取数据块,这样您就可以看到我是否做错了什么

public async Task<IEnumerable<DataTable>> GetOverViewInfoChunk(List<int> disciplineIds, List<KeyValuePair<string, bool>> statuses, DateTime startWeek, DateTime endWeek, long firstId, long lastId, int batchNumber = 10000)
{
     DateTime now = DateTime.Now;
     string procName = _config.GetValue<string>(nameof(GetOverViewInfoChunk));
     IList<Task<DataTable>> tablelistTasks = new List<Task<DataTable>>();
     long rangeCounter = firstId + batchNumber - 1;
     IEnumerable<DataTable> tables = new List<DataTable>();
     while (true)
     {
          Dictionary<string, string> @params = new Dictionary<string, string>();
          @params.Add("@disciplines", _sqlHelper.GetDisciplinesForTopAndBottom3(disciplineIds).ToString());
          @params.Add("@startWeekDate", startWeek.ToString("yyyy-MM-dd"));
          @params.Add("@lastWeekDate", endWeek.ToString("yyyy-MM-dd"));
          @params.Add("@jobStatuses", _sqlHelper.GetJobOverviewStatuses(statuses).ToString());
          @params.Add("@firstId", firstId.ToString());
          @params.Add("@lastId", rangeCounter > lastId ? lastId.ToString() : rangeCounter.ToString());
          tablelistTasks.Add(new Classes.SQLActionHelper(_config.GetValue<string>("Data:XXXX")).GetBatch(procName, @params));
                
           //Increment range vars
           firstId += batchNumber;
           rangeCounter += batchNumber;
                
           if (firstId > lastId)
             break;
      }
         
      try
      { 
          tables = await Task.WhenAll(tablelistTasks);
      }
      catch (Exception ex)
      {

      }

      TimeSpan benchMark = DateTime.Now - now;
      return tables;
}   

//class for querying the data in batches
public class SQLActionHelper
{
    private string _connStr;

    public SQLActionHelper(string connStr)
    {
        _connStr = connStr;
    }

    public async Task<DataTable> GetBatch(string procName, Dictionary<string, string> @params)
    {
        DataTable dt = null;
        //create the connection object and command object
        using (SqlConnection conn = new SqlConnection(_connStr))
        {
            using (SqlCommand command = new SqlCommand(procName, conn))
            {
                //Open the connection
                await conn.OpenAsync();

                //its a stored procedure
                command.CommandType = System.Data.CommandType.StoredProcedure;

                //Add key value pairs to the command for passing parameters to sql proc or query
                foreach (KeyValuePair<string, string> kvp in @params)
                {
                    command.Parameters.AddWithValue(kvp.Key, kvp.Value);
                }


                using (SqlDataReader reader = await command.ExecuteReaderAsync())
                {
                    dt = new System.Data.DataTable();
                    dt.Load(reader);
                    return dt;
                }
            }
        }
    }
}
public async Task GetOverViewInfoChunk(列表规则ID、列表状态、DateTime startWeek、DateTime endWeek、long firstId、long lastId、int batchNumber=10000)
{
DateTime now=DateTime.now;
字符串procName=_config.GetValue(nameof(GetOverViewInfoChunk));
IList tablelistTasks=新列表();
long rangeCounter=firstId+batchNumber-1;
IEnumerable tables=新列表();
while(true)
{
Dictionary@params=newdictionary();
@params.Add(“@prodictions”,_sqlHelper.getprodictionsfortopandbottom3(prodictioneids.ToString());
@参数Add(“@startWeekDate”,startWeek.ToString(“yyyy-MM-dd”);
@参数Add(“@lastwekdate”,endWeek.ToString(“yyyy-MM-dd”));
@params.Add(“@jobStatuses”,_sqlHelper.getjobsoverviewstatuses(statuses.ToString());
@Add(“@firstId”,firstId.ToString());
@Add(“@lastId”,rangeCounter>lastId?lastId.ToString():rangeCounter.ToString());
tablelistTasks.Add(new Classes.SQLActionHelper(_config.GetValue(“Data:XXXX”)).GetBatch(procName,@params));
//增量范围变量
firstId+=批次号;
rangeCounter+=批次号;
如果(第一个ID>最后一个ID)
打破
}
尝试
{ 
tables=等待任务.WhenAll(tablelistTasks);
}
捕获(例外情况除外)
{
}
TimeSpan基准=DateTime.Now-Now;
返回表;
}   
//用于批量查询数据的类
公共类SQLActionHelper
{
私有字符串_connStr;
公共SQLActionHelper(字符串connStr)
{
_connStr=connStr;
}
公共异步任务GetBatch(字符串procName,Dictionary@params)
{
数据表dt=null;
//创建连接对象和命令对象
使用(SqlConnection conn=newsqlconnection(_connStr))
{
使用(SqlCommand=newsqlcommand(procName,conn))
{
//打开连接
等待连接OpenAsync();
//这是一个存储过程
command.CommandType=System.Data.CommandType.StoredProcess;
//向命令中添加键值对,以便将参数传递给sql proc或查询
foreach(@params中的KeyValuePair kvp)
{
command.Parameters.AddWithValue(kvp.Key,kvp.Value);
}
使用(SqlDataReader=await命令.ExecuteReaderAsync())
{
dt=新的System.Data.DataTable();
dt.负载(读卡器);
返回dt;
}
}
}
}
}

响应时间慢的原因不是因为查询计划不好,或者数据库表没有索引,或者需要分页或技术效率低下。问题是我忽略了最基本的问题多余数据

虽然我承认我忽略了这样一个明显的设计缺陷有点尴尬,但我认为重要的是要记住,在存储数据时,尤其是当数据需要检索并在以后呈现给用户时,首先要看的是:“什么是必要的?”。虽然现在数据库存储相对便宜,但检索和显示数据库的成本却不高


我理解这篇文章的全部内容都是导致关闭的原因,因为它本身不是可复制的或编码问题,而是设计缺陷。也许它会提出一些对SO用户有用的建议。我将把这个决定留给社区和版主。感谢那些提出意见的人。

没有一个真正的人可以一次处理80k-100K行?当然有一些过滤的可能?TBH在17秒内将这么多行放在前端似乎很合理?有去b的