由于项目更新了一大版本,过不了多久就会进行一次SQL语句查询的优化任务,由运维部分导出一份历史查询SQL语句日志给开发部门做优化分析工作。以前写过一个日志分析的工具,可以不是很好,所以最近又花了几天时间,完善了这个工具。下面,我来说一下,开发历程:
一、任务分析:
1、工具界面:
2、具体需求:分类统计、忽略参数、调试错误
3、预想效果:参数部分用 ? 代替,工具效果展示:
二、开发编码:(读取(bgWorke),写入)
1、变量设置:
static string resultFile;//日志文件地址
static Dictionary Seldic, Updic, Insertdic, Deletedic, Othdic, keysDic;//Dic
static Regex patLike, patEqual, patNumber, patQo, patBE, patManySpace, patOther, patLine, patKeys;//正则
int type = 5;//SQL 语句类型
patLike = new Regex(@"(\s+like\s+)\'(.|\n)+?\'");
patEqual= new Regex(@"=\s*\'(.|\n)+?\'");
patNumber= new Regex(@"\d+");
patQo= new Regex(@"\s+(in)\s*\((\?\,)+");
patBE= new Regex(@"\BETWEEN\s+\'(.)+?\'\s+(AND)\s+\'(.)+?\'");
patManySpace= new Regex(@"\s{2,}");//空格
patOther = new Regex(@"=\s*(''|null)");
patLine= new Regex(@"\d+\s+((Init|Connect|Quit|Statistics)|(Query\s+(COMMIT|BEGIN|Show|SET|GRANT|flush)))", RegexOptions.IgnoreCase);
patKeys= new Regex(@"(\d+\s*(\d{2}\:*)+)\d+\s+(query)");keysDic= new Dictionary();//类型字典
keysDic.Add("s", 1);
keysDic.Add("i", 2);
keysDic.Add("u", 3);
keysDic.Add("d", 4);
2、读取日志:
private voidReadLog()
{int i = 0;
StreamReader sr= newStreamReader(resultFile, Encoding.UTF8);
String line;string strSQL = string.Empty;int IsNumberCount = 0;// int lineNumber = 0;//本行行号
string Number = string.Empty;while ((line = sr.ReadLine()) != null)
{if(patLine.IsMatch(line))
{continue;
}
line=line.ToLower();
line= line.Replace("\t", "");if (line.IndexOf("query") > -1)
{
IsNumberCount+= 1;if (lineNumber == 1 && IsNumberCount == 2)
{
analyzeSQLString(strSQL);
IsNumberCount= 1;
strSQL= "";
}if (lineNumber != 1 && IsNumberCount == 1)
{if (!string.IsNullOrEmpty(strSQL))
{
analyzeSQLString(strSQL);
strSQL= "";
}
}
lineNumber= 1;
strSQL= patKeys.Replace(line, "").Trim();
}else{
strSQL+= " " +line.Trim();
lineNumber++;
IsNumberCount= 0;
}
i++;if(ckDebug.Checked)
{
Thread.Sleep(1);
bgWorker.ReportProgress(i, strSQL);
}
}if (strSQL != "")
{
analyzeSQLString(strSQL);
}
sr.Close();
sr.Dispose();
}
3、语句分析
private void analyzeSQLString(stringstrSQL)
{
keysDic.TryGetValue(Convert.ToString(strSQL[0]), outtype);if(ckIgnore.Checked)
{if (type == 2)
{if (strSQL.IndexOf("values") > 0)
{
strSQL= strSQL.Substring(0, strSQL.IndexOf("values"));
}
}else{
strSQL= patManySpace.Replace(strSQL, " ");//多余空格
strSQL= patOther.Replace(strSQL, "=?");//处理 name='' 的情况
strSQL= patBE.Replace(strSQL, "between ? and ?");
strSQL= patNumber.Replace(strSQL, "?");
strSQL= patLike.Replace(strSQL, "like ?");
strSQL= patEqual.Replace(strSQL, "=?");
strSQL= patQo.Replace(strSQL, "in (");
}
}
}
3、写入文件
private void WriteLog(Dictionary data, Dictionary sort, StreamWriter sw, inti)
{if (data.Count > 0)
{
sort= data.OrderByDescending(o => o.Value).ToDictionary(o => o.Key, p =>p.Value);foreach (KeyValuePair de insort)
{
sw.Write(de.Value.ToString().PadRight(7, ' ') + " " + de.Key + "\r\n");
}
}
}
4、最终效果
链接:http://share.weiyun.com/2afd3ddfeb28675b030f5f3f976db161 (密码:7eAR)
三、最后感想:
说实话,这东西用处不是很大,但是这做这个东西的时候,加深了对正则表达式的学习。