【问题标题】:Streaming query with mssql and node, very slow the first time用mssql和node流式查询,第一次很慢
【发布时间】:2019-11-25 12:44:49
【问题描述】:

我正在使用节点 js 10.16.0 和 node-mssql 模块连接到数据库。一切正常,我的简单查询工作正常。

如果我尝试使用 node-mssql example 从查询中流式传输数据,我第一次执行时会非常慢。它不会显示超时错误,但需要大约一分钟或更长时间才能完成。

根据控制台日志,它带来了前 55 行,然后停了一会儿。根据我下面的代码,当我划分它们时,看起来在数据“集”之间需要一些时间。如果我第二次或第三次执行相同的查询,只需一秒钟即可完成。总行数约为 25.000 或更多

如何让我的流查询更快,至少是第一次

这是我的代码

按照这个例子,想法是,开始流式传输,设置 1000 行,暂停流式传输,处理这些行,使用 websocket 将它们发回,清空所有数组,继续流式传输,直到完成

let skate= [];
let leather= [];
let waterproof = [];  
let stream_start = new Date();

const request = new sql.Request(pool);
request.stream = true;     
request
.input('id_param', sql.Int, parseInt(id))
.input('start_date_param', sql.VarChar(50), startDate)
.input('stop_date_param', sql.VarChar(50), stopDate)  
.query('SELECT skate, leather , waterproof FROM shoes WHERE id = @id_param AND CAST(startTime AS date) BETWEEN @start_date_param AND @stop_date_param ');

request.on('row', row => {     
  rowc++; console.log(rowc);
  rowsToProcess.push(row); 
  if (rowsToProcess.length >= 1000) {  
    request.pause();
    processRows();
  } 
});

const processRows = () => {
  rowsToProcess.forEach((item, index) => { 
    skate.push(item.skate);  
    leather.push(item.leather );  
    waterproof.push(item.waterproof);  
  });              
  measurementsData.push(
    {title: 'Skate shoes', data: skate}, 
    {title: 'Leather shoes', data: leather}, 
    {title: 'Waterproof shoes', data: waterproof}
  );  
  console.log('another processRows done');  
  //ws.send(JSON.stringify({ message: measurementsData }));
  rowsToProcess = [];
  skate= [];
  leather= [];
  waterproof = [];       
  measurementsData = [];
  request.resume();
}

request.on('done', () => {      
  console.log('rowc , ', rowc);
  console.log('stream start , ', stream_start);
  console.log('stream done , ', new Date());
  processRows(); 
});

【问题讨论】:

  • 如果只是第一次,这听起来像是以后的查询正在使用缓存信息(计划、内存中的表等)。听起来该表的索引可能很差,或者shoesVIEW,背后有一些“复杂”的逻辑。
  • @Larnu 我的想法完全正确。那么,这是一个数据库问题吗?不,它不是视图。我应该先检查表索引吗?
  • 取决于“数据库问题”的含义。如果表的索引很差,是数据库引擎故障吗?不;它是 DBA/开发人员。我会首先查看执行计划或推回上述人员。
  • 第一件事是为鞋子的id字段添加一个非聚集索引。但只是名称指向不使用具有 100k+ 行的数据集,所以可能不是那样。
  • @smoore4 抱歉,我没听懂你对这些名字的看法。你能改写吗?谢谢

标签: sql node.js stream tedious node-mssql


【解决方案1】:

我会尝试改进shoes 表的索引。据我所知,您的查询/索引可能存在 2 个问题:

  • 您按日期时间startTime 列过滤,但只有id 列上有索引(根据 cmets)
  • 您在查询的 where 子句中将 datetime 转换为日期

索引

由于您只过滤没有时间部分的日期,我建议您创建一个新列startDate,它是将startTime 转换为日期并在其上创建索引。然后在查询中使用这个索引列。

此外,由于您仅选择 skateleatherwaterproof 列,将它们包含在索引中可以提供更好的性能。阅读indexes with included columns

如果您总是选择大于或早于某个日期的数据,那么您可以查看filtered indexes

避免在 where 中强制转换

即使通常强制转换不会花费,但在 where 子句中使用它时,它可能会阻止 SQL Server 有效使用索引。所以你should avoid it

如果您创建一个仅包含日期部分的新列并如上所述对其进行索引,则无需在此处使用强制转换:

WHERE id = @id_param AND startDate BETWEEN @start_date_param AND @stop_date_param

【讨论】:

  • 请注意,当我保留索引和强制转换时,我只执行SELECT top 10000 skate, leather , waterproof FROM shoes WHERE id = @id_param AND CAST(startTime AS date) BETWEEN @start_date_param AND @stop_date_param,然后执行f (rowsToProcess.length >= 50) { 而不是 1000,它的运行速度要快得多,而且延迟为零到零。这意味着什么?谢谢
  • 我不认为你可以得到任何结论。您应该真正在数据库端检查查询需要多少没有任何缓存。其实我不认为将node-mssql中的batch size改为50可以让它运行得更快。
【解决方案2】:

当一个查询第一次运行很慢但在随后的执行中运行很快时,正如之前有人建议的那样,这通常是由于缓存造成的。性能很可能与数据库正在运行的存储设备有关。

我希望解释计划在执行之间不会改变。

【讨论】:

  • 请注意,表的索引是id,id也是主键。我不知道这是否有什么不同。另外,我可以通过 Heidi 访问数据库。我可以做什么样的测试或设置来检查解释计划?谢谢
  • 请注意,当我保留索引和强制转换时,我只执行SELECT top 10000 skate, leather , waterproof FROM shoes WHERE id = @id_param AND CAST(startTime AS date) BETWEEN @start_date_param AND @stop_date_param,然后执行f (rowsToProcess.length >= 50) { 而不是 1000,它运行得更快,并且零延迟甚至零延迟。这意味着什么?谢谢
【解决方案3】:

您应该删除 where 子句的强制转换或创建一个计算索引(如果可能在您的数据库中)

列中的操作总是可能会损害您的查询,请尽可能避免

试着设置你的 where 参数

@start_date_param 到日期 yyyy-mm-dd 00:00:00

@stop_date_param 到日期 yyyy-mm-dd 23:59:59

AND startTime BETWEEN @start_date_param AND @stop_date_param

【讨论】:

  • 请注意,当我按原样保留索引和强制转换时,我只执行SELECT top 10000 skate, leather , waterproof FROM shoes WHERE id = @id_param AND CAST(startTime AS date) BETWEEN @start_date_param AND @stop_date_param 然后f (rowsToProcess.length >= 50) { 而不是 1000,它运行得更快,并且零延迟到零延迟。这意味着什么?谢谢
  • @codebot,尝试添加 DBCC FREEPROCCACHE 来清理缓存,以进行性能分析。或添加选项(重新编译); SELECT top 10000 skate, leather , waterproof FROM shoes WHERE id = @id_param AND CAST(startTime AS date) BETWEEN @start_date_param AND @stop_date_param OPTION (RECOMPILE) 我希望在修复演员表和/或索引之前,您所做的任何测试都会很慢
猜你喜欢
  • 2019-12-12
  • 2021-07-23
  • 1970-01-01
  • 1970-01-01
  • 2014-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-27
相关资源
最近更新 更多