本人菜鸟一只,但是我并不甘心做菜鸟,想通过一切可能的方式获得学习方法和指引。
这是一段加载树形菜单的代码,运行效率......嗯~ 很低!加载需要很长时间,有时候还会报错。
但是作为菜鸟的我不知道如何优化,这让我灰常伤心。
但是我觉得这必定也是我学习提高的机会,博客园久闻大名,也常常逛。
今天斗胆撒出自己的问题。 希望获高人指点:贴出优化方式,
指出代码中的问题(命名写法不规范,思路很低级【低级在哪儿】,
格子没对齐,不管是什么方面的意见,只要是对程序员的要求我都希望听到并学习改正),
给出您的建议,告诉我您是怎么思考的,这些思考使用什么知识做支撑的等等等等。
根据选择的设备类型执行加载代码(调用User_ShowTree方法):
1 /// <summary> 2 /// 根据设备类别显示设备及部件树 3 /// </summary> 4 /// <param name="s_Origin"></param> 5 /// <returns></returns> 6 private bool User_ShowTree(string s_Origin) 7 { 8 #region 获得类实例 9 C_DataSb_Device User_DataSb_Device = (C_DataSb_Device)GetObject("C_DataSb_Device"); 10 C_DAOSb_Device User_DAOSb_Device = (C_DAOSb_Device)GetObject("C_DAOSb_Device"); 11 C_DataPb_Code User_DataPb_Code = (C_DataPb_Code)GetObject("C_DataPb_Code"); 12 C_DAOPb_Code User_DAOPb_Code = (C_DAOPb_Code)GetObject("C_DAOPb_Code"); 13 #endregion 14 15 string s_Module = "";//设备型号 16 try 17 { 18 #region 获得对应的设备类型,不选择则查询获得所有设备类型 19 if (this.Ddl_Type.SelectedValue != "") 20 { 21 User_DataPb_Code.setPCD_Code(this.Ddl_Type.SelectedValue); 22 User_DataPb_Code.setPCD_Type("731"); 23 this.beginQuery(User_DAOPb_Code.Detail_QueryByTypeAndCode(User_DataPb_Code)); 24 } 25 else 26 { 27 this.beginQuery(User_DAOPb_Code.Detail_QueryByType("731")); 28 } 29 ArrayList list = (ArrayList)this.queryForList(); 30 #endregion 31 32 if (list.Count > 0) 33 { 34 s_Content.Append("<script type=\"text/javascript\">"); //拼接生成dTree 35 s_Content.Append("d = new dTree('d');"); 36 37 //类型循环 第一层循环 1 38 for (int k = 0; k < list.Count; k++) 39 { 40 if (s_Origin == "1" || s_Origin == "5") 41 { 42 s_Content.Append("d.add('" + ((C_DataPb_Code)list[k]).getPCD_Code() + "',-1,'" + ((C_DataPb_Code)list[k]).getPCD_Name() + "','top.Main.Right.location=\"../Sb_Jb/Sb_Jb_BaseManage.aspx?Type=" + ((C_DataPb_Code)list[k]).getPCD_Code() + "\"');"); 43 } 44 else 45 { 46 s_Content.Append("d.add('" + ((C_DataPb_Code)list[k]).getPCD_Code() + "',-1,'" + ((C_DataPb_Code)list[k]).getPCD_Name() + "','');"); 47 } 48 49 this.beginQuery(User_DAOSb_Device.Base_QueryByType(((C_DataPb_Code)list[k]).getPCD_Code())); //根据设备类型查询对应类型下的设备信息 50 DataSet Dts_Result = (DataSet)this.queryForDataSet(); //存储查询结果 51 52 if (Dts_Result != null) 53 { 54 //对应类型下设备信息循环 55 for (int i = 0; i < Dts_Result.Tables[0].Rows.Count; i++) 56 { 57 s_Content.Append("d.add('" + Dts_Result.Tables[0].Rows[i][User_DataSb_Device.Col_SDB_ID].ToString() + "','" + ((C_DataPb_Code)list[k]).getPCD_Code() + "','" + Dts_Result.Tables[0].Rows[i][User_DataSb_Device.Col_SDB_Name].ToString() + "','JsEvent(\"" + Dts_Result.Tables[0].Rows[i][User_DataSb_Device.Col_SDB_ID].ToString() + "\",\"" + Dts_Result.Tables[0].Rows[i][User_DataSb_Device.Col_SDB_Name].ToString() + "\",\"\",\"\",\"" + s_Origin + "\",\"\",\"\")');"); 58 59 //查询设备第一层部件,即筛选出SDD_Parent字段为空的记录 60 User_DataSb_Device.setSDD_Device(Dts_Result.Tables[0].Rows[i][User_DataSb_Device.Col_SDB_ID].ToString()); 61 User_DataSb_Device.setSDD_Parent(""); 62 User_DataSb_Device.setSDD_Type("101"); //只筛选指定设备部位部件 63 64 if (s_Origin == "3") 65 { 66 User_DataSb_Device.setSDD_IsCorrect("1"); //只筛选需定检部位 67 } 68 69 //查询获得对应的设备部件 70 this.beginQuery(User_DAOSb_Device.Detail_QueryByCondition(User_DataSb_Device)); 71 //存储查询结果 72 DataTable Dtb_Detail = ((DataSet)this.queryForDataSet()).Tables[0]; 73 74 //对应设备下第一层部件信息循环 75 for (int j = 0; j < Dtb_Detail.Rows.Count; j++) 76 { 77 s_Module = ""; 78 if (Dtb_Detail.Rows[j][User_DataSb_Device.Col_SDD_Model].ToString() != "") 79 { 80 s_Module = "_" + Dtb_Detail.Rows[j][User_DataSb_Device.Col_SDD_Model].ToString(); 81 } 82 //拼接菜单JS 83 s_Content.Append("d.add('" + Dtb_Detail.Rows[j][User_DataSb_Device.Col_SDD_ID].ToString() + "','" + Dts_Result.Tables[0].Rows[i][User_DataSb_Device.Col_SDB_ID].ToString() + "','" + Dtb_Detail.Rows[j][User_DataSb_Device.Col_SDD_Name].ToString() + s_Module + "','JsEvent(\"" + Dts_Result.Tables[0].Rows[i][User_DataSb_Device.Col_SDB_ID].ToString() + "\",\"" + Dts_Result.Tables[0].Rows[i][User_DataSb_Device.Col_SDB_Name].ToString() + "\",\"\",\"\",\"" + s_Origin + "\",\"" + Dtb_Detail.Rows[j][User_DataSb_Device.Col_SDD_ID].ToString() + "\",\"" + Dtb_Detail.Rows[j][User_DataSb_Device.Col_SDD_Name].ToString() + "\")','','','','');"); 84 //继续循环往下筛选更多部件信息 85 User_GetChildren(Dts_Result.Tables[0].Rows[i][User_DataSb_Device.Col_SDB_ID].ToString(), Dts_Result.Tables[0].Rows[i][User_DataSb_Device.Col_SDB_Name].ToString(), Dtb_Detail.Rows[j][User_DataSb_Device.Col_SDD_ID].ToString(), Dtb_Detail.Rows[j][User_DataSb_Device.Col_SDD_Name].ToString(), s_Origin, s_Content); 86 87 } 88 } 89 } 90 } 91 } 92 else 93 { 94 base.MessageBox_Open("设备类型未设置,请联系管理员"); 95 return false; 96 } 97 } 98 catch (Exception ex) 99 { 100 base.setWrong(ex.Message); 101 return false; 102 } 103 s_Content.Append("document.write(d);"); 104 s_Content.Append("</script> "); 105 return true; 106 } 107 108 /// <summary> 109 /// 获取部件节点信息 110 /// </summary> 111 /// <param name="s_Device"></param> 112 /// <param name="s_DeviceName"></param> 113 /// <param name="s_Parent"></param> 114 /// <param name="s_ParentName"></param> 115 /// <param name="s_Origin"></param> 116 /// <param name="s_Content"></param> 117 private void User_GetChildren(string s_Device, string s_DeviceName, string s_Parent, string s_ParentName, string s_Origin, StringBuilder s_Content) 118 { 119 #region 获取类实例,赋值筛选条件 120 C_DataSb_Device User_DataSb_Device = (C_DataSb_Device)GetObject("C_DataSb_Device"); 121 C_DAOSb_Device User_DAOSb_Device = (C_DAOSb_Device)GetObject("C_DAOSb_Device"); 122 123 User_DataSb_Device.setSDD_Device(s_Device); 124 User_DataSb_Device.setSDD_Parent(s_Parent); 125 User_DataSb_Device.setSDD_Type("101"); //只筛选指定部位的设备部件 126 127 if (s_Origin == "3") 128 { 129 User_DataSb_Device.setSDD_IsCorrect("1"); //只筛选需定检部位 130 } 131 #endregion 132 133 string s_Module = "";//部件型号 134 try 135 { 136 //查询某节点下的子节点信息(即查询某设备部件包含的明细部件信息) 137 this.beginQuery(User_DAOSb_Device.Detail_QueryByDeviceAndParent(User_DataSb_Device)); 138 DataTable Dtb_Detail = ((DataSet)this.queryForDataSet()).Tables[0]; 139 140 //循环查询结果 141 for (int i = 0; i < Dtb_Detail.Rows.Count; i++) 142 { 143 s_Module = ""; 144 if (Dtb_Detail.Rows[i][User_DataSb_Device.Col_SDD_Model].ToString() != "") 145 { 146 s_Module = "_" + Dtb_Detail.Rows[i][User_DataSb_Device.Col_SDD_Model].ToString(); 147 } 148 s_Content.Append("d.add('" + Dtb_Detail.Rows[i][User_DataSb_Device.Col_SDD_ID].ToString() + "','" + s_Parent + "','" + Dtb_Detail.Rows[i][User_DataSb_Device.Col_SDD_Name].ToString() + s_Module + "','JsEvent(\"" + s_Device + "\",\"" + s_DeviceName + "\",\"" + s_Parent + "\",\"" + s_ParentName + "\",\"" + s_Origin + "\",\"" + Dtb_Detail.Rows[i][User_DataSb_Device.Col_SDD_ID].ToString() + "\",\"" + Dtb_Detail.Rows[i][User_DataSb_Device.Col_SDD_Name].ToString() + "\")','','','','');"); 149 150 User_GetChildren(s_Device, s_DeviceName, Dtb_Detail.Rows[i][User_DataSb_Device.Col_SDD_ID].ToString(), Dtb_Detail.Rows[i][User_DataSb_Device.Col_SDD_Name].ToString(), s_Origin, s_Content); 151 } 152 153 } 154 catch (Exception ex) 155 { 156 base.setWrong(ex.Message); 157 return; 158 } 159 }
queryForDataSet 这个方法是做什么的呢.?是读取数据库么.?或是读配置文件.?
如果是的话.这里应该是一个可优化的地方,多次循环读库,会造成效率问题,
建议你一次把数据都读到内容里,然后再从内存里做筛选操作
还有就是,请不要用弱类型来操作数据,会造成多次装箱拆箱,也会影响效率.
是查询方法 用的iBATIS
@三年二班: 建议你减少与数据库交互的次数,
一次性读出所有所需要显示的数据,
然后在内存里处理数据,显示到窗口上,
尽量减少内与数据库交互次数
我的QQ
hh-jm19890727@163.com如果不明白.再问我.
@发粪图墙: 感谢你的回答 根据你的建议已经做了优化 谢谢
1、不展开全部子节点
2、如果必须展开全部子节点,起一个事务,全部查询完成后,关闭事务。
树形的结构显示时最好不展开下层,点+号再插入下一层,查找符合当前节点的子节点,顺序插入
生成树结构可以尝试递归方法,需要展开的数据全部加载,从root开始循环,递归方法插入子孙节点
没有仔细看,
1楼说的挺好的,是否有在递归里做数据库查询。 这样确实会很慢。
问题分析:
stack overflow, at line: 657
这个说明 栈溢出了, 检查行 657代码.
看代码, 最可能的原因: User_GetChildren()中存在递归调用, 如果某中条件下陷入循环死递归,
则这种情况必然触发栈溢出.
请检查 递归部分是否存在逻辑漏洞, 会限制循环递归.
主要问题:
1. User_GetChildren()中存在 可能不够安全(死循环)的 递归调用.
2. sql访问次数太多.
User_ShowTree()中 有三重循环, 做太多次sql操作了.
需要优化.