TypeScript查询SQL Server远慢于C#,如何优化提速?
我在C#和TypeScript中实现了逻辑相同的数据获取代码,两者调用同一个SQL Server数据库的表和存储过程,但执行效率差异极大:C#版本仅需5秒完成,TypeScript版本却耗时189秒。
C#代码实现
foreach (var p in proglist) { programData.GetData1= new List<GetData1_ViewModel>(GetData1(programid, reportingdate)); programData.GetData2= new List<GetData2_ViewModel>(GetData2(programid, reportingdate)); programData.GetData3= new List<GetData3_ViewModel>(GetData3(programid, reportingdate)); programData.GetData4= new List<GetData4_ViewModel>(GetData4(programid, reportingdate)); programData.GetData5= new List<GetData5_ViewModel>(GetData5(programid, reportingdate)); }
TypeScript代码实现
for (const p of proglist) { this.data1 = []; this.data2 = []; this.data3 = []; this.data4 = []; this.data5 = []; await Promise.all([ (this.data1 = await this.GetMeasureForScorecard(p.programId, reportingdate, "GetData1")), (this.data2 = await this.GetMeasureForScorecard(p.programId, reportingdate, "GetData2")), (this.data3 = await this.GetMeasureForScorecard(p.programId, reportingdate, "GetData3")), (this.data4 = await this.GetData4(p.programId, reportingdate, "GetData4")), (this.data5 = await this.GetData5(p.programId, reportingdate, "GetData5")), ]); }
修复
Promise.all的错误用法:当前代码在Promise.all数组内直接使用await,导致5个请求变成串行执行,完全浪费了Promise.all的并行能力。正确写法应该是将异步调用的Promise直接传入数组,通过then赋值:await Promise.all([ this.GetMeasureForScorecard(p.programId, reportingdate, "GetData1").then(res => this.data1 = res), this.GetMeasureForScorecard(p.programId, reportingdate, "GetData2").then(res => this.data2 = res), this.GetMeasureForScorecard(p.programId, reportingdate, "GetData3").then(res => this.data3 = res), this.GetData4(p.programId, reportingdate, "GetData4").then(res => this.data4 = res), this.GetData5(p.programId, reportingdate, "GetData5").then(res => this.data5 = res), ]);原写法相当于每个请求必须等上一个完成才发起,而C#的同步/并行调用能大幅节省时间。
检查数据库连接复用:C#默认通过连接池复用数据库连接,而TypeScript如果是前端直连数据库、或调用的后端服务未配置连接池,会导致每次请求新建连接,放大连接建立的开销。确认TypeScript侧(或其依赖的后端)是否开启并合理配置了数据库连接池。
对比网络架构差异:如果TypeScript是前端代码,每个请求都要经过"前端→后端→数据库"的网络往返;而C#如果是后端直连数据库,网络开销会小很多。这种情况下可以考虑将多个数据请求合并为单个后端接口,减少网络往返次数。
验证SQL执行计划一致性:确认TypeScript传递给存储过程的参数类型、格式和C#完全一致,避免因隐式类型转换导致SQL Server生成低效执行计划(比如全表扫描)。可以用SQL Server Profiler或Extended Events捕获两边的执行语句,对比执行时间和计划。
批量处理
proglist:如果proglist数量较多,C#可能是并行遍历或批量处理,而TypeScript是串行遍历每个p。可以尝试将proglist的处理并行化(注意控制并发量避免数据库过载),或分批次处理。排查序列化开销:TypeScript中如果返回数据量较大,JSON序列化/反序列化的开销可能高于C#。可以检查返回数据是否包含冗余字段,或改用更高效的序列化格式(如MessagePack)。
内容的提问来源于stack exchange,提问作者FlyFish

