VB.NET中合并两个SQL查询优化DataGridView大数据加载速度
你当前性能瓶颈的核心是逐行查询的N+1访问模式,数据量越大耗时越高,直接将两次查询逻辑合并为单次数据库查询即可实现数量级的性能提升,具体方案如下:
合并查询实现思路
将第二段查询中「按pcode匹配最新newprice」的逻辑封装为CTE(公共表表达式),和第一段的聚合查询直接关联,一次性返回所有需要的字段,彻底消灭应用层循环发起的多次数据库请求。
合并后的SQL语句
WITH LatestPriceCTE AS ( -- 对应原查询2逻辑,预计算所有pcode的最新有效newprice SELECT pcode, newprice, ROW_NUMBER() OVER ( PARTITION BY pcode ORDER BY CAST(pdate AS date) DESC, CAST(pp AS int) DESC ) AS row_num FROM producth WHERE details IN ('اذن اضافة مشتريات', 'اذن تسوية جردية مدينة', 'إضافة رصيد افتتاحي') AND pdate <= @ad ) -- 原查询1的聚合逻辑,关联CTE取最新价格 SELECT products.psize, producth.pcode, producth.pname, COALESCE(SUM(CAST(CASE WHEN producth.details IN ('اذن اضافة مشتريات', 'اذن تسوية جردية مدينة', 'إضافة رصيد افتتاحي', 'اذن اضافة مرتجعات مبيعات') THEN CAST(producth.quanitity AS money) ELSE 0 END AS money)), 0) AS tadd, COALESCE(SUM(CAST(CASE WHEN producth.details IN ('اذن صرف مبيعات', 'اذن تسوية جردية دائنة', 'اذن ترجيع مشتريات') THEN CAST(producth.quanitity AS money) ELSE 0 END AS money)), 0) AS tremove, COALESCE(lp.newprice, 0.000) AS newprice FROM producth INNER JOIN products ON products.parcode = producth.pcode LEFT JOIN LatestPriceCTE lp ON producth.pcode = lp.pcode AND lp.row_num = 1 WHERE producth.pdate <= @ad GROUP BY producth.pcode, producth.pname, products.psize, lp.newprice
优化后的VB.NET代码
同步修改为参数化查询,避免SQL注入风险和日期格式兼容性问题:
Dim sqqq As String = "上述合并后的SQL语句" Dim cmdd As New SqlCommand(sqqq, con) ' 用参数传递日期值,自动适配数据库格式 cmdd.Parameters.AddWithValue("@ad", ad) Dim dddr As SqlDataReader = cmdd.ExecuteReader DataGridView1.Rows.Clear() While dddr.Read DataGridView1.Rows.Add( DataGridView1.Rows.Count + 1, dddr("pcode"), dddr("pname"), dddr("psize"), "0.000", dddr("newprice"), "0.000" ) End While dddr.Close()
修改后完全不需要保留原有的逐行查询循环逻辑。
额外性能优化建议
- 给
producth表创建联合索引:(pcode, details, pdate),覆盖查询条件可以大幅减少扫描的数据量 - 如果
pp字段经常用于排序、最大值计算,也可以加入上述索引中进一步提速
内容的提问来源于stack exchange,提问作者Osama Gadour
相关产品推荐
相关产品推荐

