由於項目更新了一大版本,過不了多久就會進行一次SQL語句查詢的優化任務,由運維部分導出一份歷史查詢SQL語句日志給開發部門做優化分析工作。以前寫過一個日志分析的工具,可以不是很好,所以最近又花了幾天時間,完善了這個工具。下面,我來說一下,開發歷程:
一、任務分析:
1、工具界面:
2、具體需求:分類統計、忽略參數、調試錯誤
3、預想效果:參數部分用 ? 代替,工具效果展示:
二、開發編碼:(讀取(bgWorke),寫入)
1、變量設置:
static string resultFile;//日志文件地址 static Dictionary<string, int> 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<string, int>();//類型字典 keysDic.Add("s", 1); keysDic.Add("i", 2); keysDic.Add("u", 3); keysDic.Add("d", 4);
2、讀取日志:
private void ReadLog() { int i = 0; StreamReader sr = new StreamReader(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(string strSQL) { keysDic.TryGetValue(Convert.ToString(strSQL[0]), out type); 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<String, int> data, Dictionary<String, int> sort, StreamWriter sw, int i) { if (data.Count > 0) { sort = data.OrderByDescending(o => o.Value).ToDictionary(o => o.Key, p => p.Value); foreach (KeyValuePair<string, int> de in sort) { sw.Write(de.Value.ToString().PadRight(7, ' ') + " " + de.Key + "\r\n"); } } }
4、最終效果
鏈接:http://share.weiyun.com/2afd3ddfeb28675b030f5f3f976db161 (密碼:7eAR)
三、最后感想:
說實話,這東西用處不是很大,但是這做這個東西的時候,加深了對正則表達式的學習。