最近公司严打,没办法。只能想办法帮同事修改他们一些查询比较慢的代码。下面我总结下我再给他们优化查询的时候遇到的一些问题和解决方案。(索引已经考虑过了。)
多表并且带有运算的查询优化。
数据列为20需要绑定到Datagridview上面,表的链接数为3,每个表分别有上10W的数据。
数据绑定的结果为15W。花时2分-3分钟。(前提条件远程服务器访问,网络不稳定)
客户查询效果是假死。
解决方法:
1. 用时间间隔来测试问题是出现在数据库查询语句,还是我们PC代码处理阶段,甚至是绑定时。
(在我帮公司其他员工优化查询的时候,这几个问题都纷纷出现了。)
下面我写个思路给大家参考:
<出库履历查询!-->
DateTime dTimeStart = DateTime.Now;
--1.查询出库记录
txtTimeRecord.Text += "\r\n" + "开始时间:" + dTimeStart.ToString() + "结束时间:" + DateTime.Now.ToString();
优化SQL语句:
1. 函数
1)尤其是涉及到计算的函数,尽量不要使用,可以简化到PC段代码去处理,就简化到PC段代码去处理。当然,这个需要你去测试才知道对你的查询效率是否影响。测试也简单,就算去掉计算函数,查询同样多的数据,查看查询效率,如果在1-2秒范围内的话,就没必要去处理了。
2)关键字使用,如Like的使用等。
2.数据比较
使用同种类型进行数据比较。
如:Datetime类型
由于有的公司不是用参数化进行数据查询的,所以,很多员工可能会忘记当SQL语句,当你的Datetime类型写入SQL语句的时候,数据比对就会出现Datetime和String两个类型进行比对了。这样有的时候还会出现查询误差。当然,查询效率的话,也会有很大的影响的。上万数据效率差多则可达1分钟以上的效率差距。
--2.计算出库数量
txtTimeRecord.Text += "\r\n" + "开始时间:" + dTimeStart.ToString() + "结束时间:" + DateTime.Now.ToString();
代码逻辑优化:
减少数据库的访问次数,尽量一次性取出数据,PC段处理。按照这个原则,去优化你的代码。
如:
--DataTable dTable1=...
for(dTable1..)
{
--DataTable dTable2=.. where a=dTable1.Row[?][?].ToString();
for(dTable2..)
{
--计算
}
}
上面这个大家应该都很熟悉吧,不熟悉以后说明你代码写得太少了,呵呵!开玩笑啦,言归正传!
上面的代码可以有如下优化:
--DataTable dTable1=...
--DataTable dTable2=..
foreach(dTable1..)
{
--DataRow[] dr2=.. Select( a=dTable1.Row[?][?].ToString());
foreach(dr2..)
{
--计算
}
}
如果是本机测试的话,这两段代码的处理效率是差不多的,但是如果是网络远程访问的话,效率就截然不同了,6000条数据来讲吧,下面的处理1-3秒,
上面的处理,会出现20秒左右的假死。当然这个数字仅仅是估算的,因为实际情况太多了,我们没有那个时间去具体化。
这种情况可能出现的比较多,因为我们中小型公司很多时候,都是本机测试,然后给测试人员测试。
--3.绑定出库履历Datagridview
txtTimeRecord.Text += "\r\n" + "开始时间:" + dTimeStart.ToString() + "结束时间:" + DateTime.Now.ToString();
这个有人会这样讲,绑定不救那么一两句话可以搞定了嘛,怎么还能优化?扯淡嘛,不是!
不错,你的想法是对的,如果我还是一个普通员工的话,我会那样想。但是可能是我现在是一个领导,提报的任何问题我都必须给一个满意的回复,所以我会把这句话抛于脑后。去查看Datagridview的用法,看看是否能找出一些猫咪。
果然被我发现了一些猫咪,经过我的有些同事也发现了,可是由于经验没我丰富吧,所以没有利用好他们发现的方法。
Datagridview的排序、根据数据长度自动调整显示框显示宽度等功能也许大家有的时候,觉得很好用吧,的确,但是有句话说得好,一个食物的诞生,必然有它的好处和坏处。这里的坏处就是影响了绑定的效率。可能5W以内的绑定效果看不出来,但是10W、15W等,很容易看出来了。
所以这些花哨的功能尽量自己重写,或者换另外的方式实现。这样绑定效率也就会提高了。
下面我讲下我问题的解决方法吧。
我这边主要是AutoSizeMode的设置在作怪,因为客户需要一个“根据数据长度自动调整显示框显示宽度”的功能,他不考虑列头的汉字是否能够显示完全。
我的同事告诉我,他已经设置了,没有效果。后来我发现,他确实设置了,但是设置的事整个Datagridview的AutoSizeMode。没有考虑单个列的AutoSizeMode。这两个设置起主导作用的还是单个立的AutoSizeMode属性,讲起设置为none。
至于“根据数据长度自动调整显示框显示宽度”的功能的话,我是用下面的方法实现的。
在绑定之后,通过如下计算每一列的数据最长的长度,来设置列的宽度。
ArrayList aLst = new ArrayList();
for (int i = 0; i < ds.Tables[0].Columns.Count - 3; i++)
{
int iLength = 0;
foreach (DataRow item in ds.Tables[0].Rows)
{
string str = item[i].ToString();
int iCount = 0;
for (int j = 0; j < str.Length; j++)
{
if (Char.ConvertToUtf32(str, i) >= Convert.ToInt32("4e00", 16) && Char.ConvertToUtf32(str, i) <= Convert.ToInt32("9fff", 16))
{
iCount++;//统计汉字
}
}
int iItemLength = item[i].ToString().Length + iCount;
if (iLength < iItemLength)
{
iLength = iItemLength;
}
}
aLst.Add(iLength.ToString());
}
for(int i=1;i
解释下:
我估算的一个字母占用列表的宽度为7.如果有笔误的话,还请提出来,我修改。
4. 今天优化时,又发现了一个新手经常容易发错的写法,写出来大家分享
方法
{
for(...)
{
查询语句:
strSql=。。。 dtpInDateFrom.Value.ToString("s").Substring(0, 10)....;
}
}
dtpInDateFrom是时间控件
看起来很合情合理。
但实际上是不合理的。
方法
{
string strDtime=dtpInDateFrom.Value.ToString("s").Substring(0, 10);
for(...)
{
查询语句:
strSql=。。。 strDtime(时间比较)....;
}
}
看看下面的写法,这两种写法,在执行效率上是很有区别的,下面的执行效率高于上面的10倍(估算的,不太准确,知道意思就行)。
其他的情况我就暂时不举例了,因为我也没有处理过,我只是提出这么一个观点给大家分享,如果觉得还想问什么的话,请留言,我会一一告诉您。