You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NestJS调用SQL Server原生SQL性能低下,是否为配置问题?

解决NestJS + mssql连接SQL Server的性能延迟问题

核心问题分析

你的代码存在两个关键问题导致查询延迟:

  • 数据库连接池初始化未等待完成,且池配置不合理,导致查询时可能频繁创建新连接
  • 采用字符串拼接生成SQL,不仅存在SQL注入风险,还额外增加了SQL解析开销,无法有效复用连接池资源

具体修复步骤

1. 等待连接池初始化完成后启动应用

原main.ts中sql.connect(sqlConfig)是异步操作,但未加await,导致应用启动时连接池尚未建立,第一次查询会触发连接建立流程,直接增加延迟。修改如下:

async function bootstrap() {
  // ... 其他代码保持不变
  // 等待连接池初始化完成
  await sql.connect(sqlConfig);
  logger.log('App connected to SQL Server database');
  // ... 其他代码保持不变
}

2. 调整连接池配置,避免频繁销毁连接

原配置min: 0会导致空闲时关闭所有连接,每次新请求都需要重新建立连接,在Azure环境下网络开销极大。修改pool配置:

pool: {
  max: 10,
  min: 3, // 保持3个空闲连接,避免频繁创建
  idleTimeoutMillis: 60000, // 延长空闲超时到1分钟
},

3. 改用参数化调用存储过程,放弃字符串拼接

原代码的SQL拼接方式无法利用连接池的预编译和复用能力,同时存在严重的注入风险。修改CrudService的查询逻辑,使用mssql的Request对象调用存储过程:

async find(
  sp: string,
  DB: string,
  body?: FindBodyDTO | null,
  query?: Record<string, any> | null,
  email?: string,
  filter?: string,
): Promise<Record<string, any>[]> {
  const method = 'find';
  const storedProcedure = process.env.SPECIFYDB == 'true'
    ? `[${DB}].[ml_sp].[${sp}]`
    : `[ml_sp].[${sp}]`;

  try {
    const request = new sql.Request();
    // 绑定参数,避免字符串拼接
    request.input('method', sql.NVarChar, method);
    request.input('body', sql.NVarChar, body ? JSON.stringify(body) : null);
    request.input('query', sql.NVarChar, query ? JSON.stringify(query) : null);
    request.input('email', sql.NVarChar, email);
    request.input('filter', sql.NVarChar, filter);
    
    // 执行存储过程
    const result = await request.execute(storedProcedure);
    return result.recordset as Record<string, any>[];
  } catch (error) {
    this.logger.error(error);
    throw new HttpException(
      fxSQLerrorMsg(error.message, 'Find'),
      HttpStatus.BAD_REQUEST,
    );
  }
}

注意:需同步修改存储过程的参数接收逻辑,确保与传入参数名匹配。

4. 验证连接池复用情况

添加日志监听连接池的连接创建与释放事件,确认连接是否被复用:

// 在main.ts连接完成后添加
sql.on('connect', (connection) => {
  logger.log(`新连接创建,ID: ${connection.id}`);
});

sql.on('release', (connection) => {
  logger.log(`连接释放,ID: ${connection.id}`);
});

若多次查询复用同一个连接ID,说明连接池已生效。


额外优化建议

  • Azure SQL Server:将应用部署在与数据库同区域的服务器上,降低网络延迟
  • 确认Azure SQL的Connection Pooling选项处于开启状态(默认开启)
  • 避免重复序列化JSON对象,可提前处理参数后再传入查询

内容的提问来源于stack exchange,提问作者John G.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 19:15:51