SQL日志分析的一个小工具

最近要调优SQL语句,于是运维倒了一份SQL日志给我,我需要知道那一些是查询慢,更新多,总之就是哪些语句执行多。

1、需要将MySQL日志解析:例如:

2、需要实现成:

思路:

1、SQL语句分类:SELECT、UPDATE、INSERT、DELETE(增、删,改,查)

2、针对更新语句、插入语句单独处理

3、正则匹配、字符串Split

4、Dictionary<string, int>键值组合

5、异步读写

开始代码:

1、正则表达式:

 /// <summary>
        /// 关键的运算付
        /// </summary>
        string[] keys = { "<", ">", "=", "!=" };

        /// <summary>
        /// 匹配Lik和in
        /// </summary>
        Regex patLike = new Regex(@"(\b)(like|in)(\b)", RegexOptions.IgnoreCase);
        //时间
        Regex patTime = new Regex(@"(\d{2}|\d{4})(?:\-)?([0]{1}\d{1}|[1]{1}[0-2]{1})(?:\-)?([0-2]{1}\d{1}|[3]{1}[0-1]{1})(?:\s)?([0-1]{1}\d{1}|[2]{1}[0-3]{1})(?::)?([0-5]{1}\d{1})(?::)?([0-5]{1}\d{1})|([\d+]{4}\/[\d+]{1,2}\/[\d+]{1,2} [\d+]{2}\:[\d+]{2}\:[\d+]{2})", RegexOptions.IgnoreCase);

        //带SQL运算符
        Regex patSql = new Regex(@"(=|<|>|<=|>=|!=|<>|like|in\s+\(|in\()(\s+\S+)|(=|<|>|<=|>=|!=|<>|like|in\s+\(|in\()(\S+)", RegexOptions.IgnoreCase);

        /// <summary>
        /// 获取单词
        /// </summary>
        Regex patArry = new Regex(@"([a-z_]+)");

        /// <summary>
        /// 字符集合
        /// </summary>
        MatchCollection matchsMade;

2、读取文件:

 1 //resultFile 文件全路径
 2 StreamReader sr = new StreamReader(resultFile, Encoding.UTF8);
 3             int i = 0;
 4             String line;
 5             string strSQL = string.Empty;
 6             int IsNumberCount = 0;//
 7             int lineNumber = 0;//本行行号
 8             string Number = string.Empty;
 9
10             string[] KeysArry = { "init", "connect", "quit", "statistics", "begin", "show", "commit" };
11
12             bool isKeys = false;
13             while ((line = sr.ReadLine()) != null)
14             {
15                 i++;
16                 line = line.Trim();//去除首位空白
17                 line = line.ToLower();
18                 isKeys = false;
19                 foreach (string s in KeysArry)
20                 {
21                     if (line.IndexOf(s) > -1)
22                     {
23                         isKeys = true;
24                         continue;
25                     }
26                 }
27                 if (isKeys)
28                 {
29                     continue;
30                 }
31                 line = line.Replace("\t", "");
32
33                 if (line.IndexOf("query") > -1)
34                 {
35                     IsNumberCount += 1;
36                     if (lineNumber == 1 && IsNumberCount == 2)
37                     {
38                         analyzeSQLString(strSQL);
39                         IsNumberCount = 1;
40                         strSQL = "";
41                     }
42                     if (lineNumber != 1 && IsNumberCount == 1)
43                     {
44                         if (!string.IsNullOrEmpty(strSQL))
45                         {
46                             analyzeSQLString(strSQL);
47                             strSQL = "";
48                         }
49                     }
50                     lineNumber = 1;
51                     Number = line.Split(‘ ‘).Length > 0 ? line.Split(‘ ‘)[0] : "";
52                     strSQL = line.ToString();
53                     strSQL = strSQL.Substring(Number.Length);
54                     strSQL = strSQL.Replace("query", "");
55                     strSQL = strSQL.Trim();
56
57                 }
58                 else
59                 {
60                     strSQL += " " + line.ToString();
61                     lineNumber++;
62                     IsNumberCount = 0;
63                 }
64                 bgWorker.ReportProgress(i);
65                 if (bgWorker.CancellationPending)
66                 {
67                     e.Cancel = true;
68                     return;
69                 }
70                 Thread.Sleep(SleepMis);
71
72             }
73             if (strSQL != "")
74             {
75                 analyzeSQLString(strSQL);
76             }
77             CountLine = i;
78             sr.Close();
79             sr.Dispose();

3、SQL解析-----analyzeSQLString(string strSQL)

 #region SQL解析
        private void analyzeSQLString(string strSQL)
        {
            int t = 1;
            int idx = 0;
            if (strSQL.IndexOf("select") > -1)
            {
                t = 1;
                idx = strSQL.IndexOf("select");
            }
            else if (strSQL.IndexOf("insert") > -1)
            {
                t = 2;
                idx = strSQL.IndexOf("insert");
            }
            else if (strSQL.IndexOf("update") > -1)
            {
                t = 3;
                idx = strSQL.IndexOf("update");
            }
            else if (strSQL.IndexOf("delete") > -1)
            {
                t = 4;
                idx = strSQL.IndexOf("delete");
            }
            else
            {
                t = 5;
            }
            if (idx != 0)
            {
                strSQL = strSQL.Substring(idx);
            }
            switch (t)
            {
                case 1://查询
                    {
                        //过滤参数
                        if (ckIgnore.Checked)
                        {
                            //过滤limit
                            if (strSQL.LastIndexOf("limit") > 0)
                            {
                                strSQL = strSQL.Substring(0, strSQL.LastIndexOf("limit"));
                                strSQL = strSQL.Trim();
                            }
                            //过滤order by
                            if (strSQL.Contains("order by"))
                            {
                                strSQL = strSQL.Substring(0, strSQL.LastIndexOf("order by"));
                                strSQL = strSQL.Trim();
                            }
                            strSQL = RegexString(strSQL);
                        }
                        if (Seldic.ContainsKey(strSQL))
                        {
                            Seldic[strSQL] = Convert.ToInt32(Seldic[strSQL]) + 1;
                        }
                        else
                        {
                            Seldic.Add(strSQL, 1);
                        }
                    }; break;
                case 2://插入
                    {
                        //过滤参数
                        if (ckIgnore.Checked)
                        {
                            if (strSQL.LastIndexOf("values") > 0)
                            {
                                strSQL = strSQL.Substring(0, strSQL.LastIndexOf("values"));
                            }
                        }
                        if (Insertdic.ContainsKey(strSQL))
                        {
                            Insertdic[strSQL] = Convert.ToInt32(Insertdic[strSQL]) + 1;
                        }
                        else
                        {
                            Insertdic.Add(strSQL, 1);
                        }

                    }; break;
                case 3://更新
                    {
                        //过滤参数
                        if (ckIgnore.Checked)
                        {
                            matchsMade = patArry.Matches(strSQL);
                            strSQL = "";
                            for (int i = 0, len = matchsMade.Count; i < len; i++)
                            {
                                if (i < 3)
                                {
                                    strSQL += matchsMade[i].Value + " ";
                                }
                                else
                                {
                                    if (matchsMade[i].Value != "where")
                                    {
                                        strSQL += matchsMade[i].Value + "=? ";
                                    }
                                    else
                                    {
                                        strSQL += matchsMade[i].Value + " ";
                                    }
                                }
                            }
                            strSQL = strSQL.TrimEnd();

                            #region 老
                            //string strTable = string.Empty, strWhere = string.Empty;
                            //int idxwhere = strSQL.LastIndexOf("where");
                            //if (idxwhere > 0)
                            //{
                            //    strWhere = RegexString(strSQL.Substring(idxwhere));

                            //    strSQL = strSQL.Substring(0, idxwhere);
                            //    strSQL = strSQL.Trim();
                            //}
                            //strTable = strSQL.Substring(0, strSQL.IndexOf("set"));
                            //strSQL = strSQL.Substring(strSQL.IndexOf("set") + 3);
                            //strSQL = RegRepac(strSQL).Trim();
                            ////解析
                            //foreach (string s in strSQL.Split(‘B‘))
                            //{
                            //    if (s.Split(‘A‘).Length > 1)
                            //    {
                            //        strSQL = strSQL.Replace(s, s.Split(‘A‘)[0] + "[email protected]");
                            //    }
                            //}
                            //strSQL = strSQL.Replace("B", ",");
                            //strSQL = strTable + "set " + strSQL + (string.IsNullOrEmpty(strWhere) ? "" : " " + strWhere);
                            #endregion 老

                        }
                        if (Updic.ContainsKey(strSQL))
                        {
                            Updic[strSQL] = Convert.ToInt32(Updic[strSQL]) + 1;
                        }
                        else
                        {
                            Updic.Add(strSQL, 1);
                        }

                    }; break;
                case 4://删除
                    {
                        //过滤参数
                        if (ckIgnore.Checked)
                        {
                            strSQL = RegexString(strSQL);
                        }
                        if (Deletedic.ContainsKey(strSQL))
                        {
                            Deletedic[strSQL] = Convert.ToInt32(Deletedic[strSQL]) + 1;
                        }
                        else
                        {
                            Deletedic.Add(strSQL, 1);
                        }

                    }; break;
                default://其它
                    {
                        if (Othdic.ContainsKey(strSQL))
                        {
                            Othdic[strSQL] = Convert.ToInt32(Othdic[strSQL]) + 1;
                        }
                        else
                        {
                            Othdic.Add(strSQL, 1);
                        }
                    }; break;
            }
        }

        #endregion

4、写入文件:

 1 private void Write()
 2         {
 3             FileStream fs = new FileStream(System.Environment.CurrentDirectory + "\\sql.txt", FileMode.Create);
 4             StreamWriter sw = new StreamWriter(fs, Encoding.UTF8);
 5             //开始写入
 6             Dictionary<string, int> sortdic = new Dictionary<string, int>();
 7             sw.Write("查询操作\r\n");
 8             sw.Write("-----------------------------------------------------------\r\n");
 9             WriteLog(Seldic, sortdic, sw, 0);
10
11             sw.Write("插入操作\r\n");
12             sw.Write("-----------------------------------------------------------\r\n");
13             WriteLog(Insertdic, sortdic, sw, 1);
14
15             sw.Write("更新操作\r\n");
16             sw.Write("-----------------------------------------------------------\r\n");
17             WriteLog(Updic, sortdic, sw, 2);
18
19
20             sw.Write("删除操作\r\n");
21             sw.Write("-----------------------------------------------------------\r\n");
22             WriteLog(Deletedic, sortdic, sw, 3);
23
24             sw.Write("其它操作\r\n");
25             sw.Write("-----------------------------------------------------------\r\n");
26             WriteLog(Othdic, sortdic, sw, 4);
27
28             //清空缓冲区
29             sw.Flush();
30             //关闭流
31             sw.Close();
32             fs.Close();
33         }
34
35
36         private void WriteLog(Dictionary<String, int> data, Dictionary<String, int> sort, StreamWriter sw, int i)
37         {
38             if (data.Count > 0)
39             {
40                 sort = data.OrderByDescending(o => o.Value).ToDictionary(o => o.Key, p => p.Value);
41                 foreach (KeyValuePair<string, int> de in sort)
42                 {
43                     sw.Write(de.Value.ToString().PadRight(7, ‘ ‘) + "   " + de.Key + "\r\n");
44                 }
45                 bgWaritWorke.ReportProgress(i);
46                 Thread.Sleep(SleepMis);
47             }
48         }

5、异步读写

6、最关键的正则解析

 #region 正则过滤参数

        /// <summary>
        /// 正则过滤参数
        /// </summary>
        /// <param name="s">带解析字符串</param>
        /// <returns></returns>
        public string RegexString(string strSQL)
        {
            // "<", ">", "<=", ">=", "!=", "<>", "="
            //(\b|\b\s+|\‘)(,)
            //(\b|\b\s+)(=)
            //(\=\w+\,)|(\=\s+\w+\,)|(\=\‘\w+\‘\,)|(\=\s\‘\w+\‘\,)|(\‘\,)

            strSQL = patTime.Replace(strSQL, "@p"); //时间
            strSQL = patSql.Replace(strSQL, "@p"); //参数 

            #region 老
            //int r = 0, len = 0;
            //temp = key = "";
            ////带SQL运算符
            //matchsMade = patSql.Matches(strSQL);
            //for (r = 0, len = matchsMade.Count; r < len; r++)
            //{
            //    //取出前缀关键字
            //    temp = matchsMade[r].Value;
            //    key = "";
            //    if (patLike.IsMatch(temp))
            //    {
            //        key = patLike.Matches(temp)[0].Value;
            //    }
            //    else
            //    {
            //        foreach (string t in keys)
            //        {
            //            if (temp.Replace(t, "").Length < temp.Length)
            //            {
            //                temp = temp.Replace(t, "");
            //                key += t;
            //            }
            //        }
            //    }

            //    //重新赋值
            //    temp = matchsMade[r].Value;
            //    if (temp.IndexOf(key) > 0)
            //    {
            //        temp = temp.Substring(0, temp.IndexOf(key));
            //    }
            //    strSQL = strSQL.Replace(matchsMade[r].Value, temp + " " + key + "@p");
            //    key = "";
            //}
            #endregion

            return strSQL;
        }

        /// <summary>
        /// 替换
        /// </summary>
        /// <param name="strSQL"></param>
        /// <param name="newValue"></param>
        /// <returns></returns>
        public string RegRepac(string strSQL)
        {
            //(\b|\b\s+|\‘)(,)
            //(\b|\b\s+)(=)
            Regex pat = new Regex(@"(\b|\b\s+|`)(=)");
            strSQL = pat.Replace(strSQL, "A");
            pat = new Regex(@"(\b|\b\s+|\‘)(,)");
            strSQL = pat.Replace(strSQL, "B");
            return strSQL;
        }

        #endregion

完整的实例:

=================================================================================================================================================

所遇问题:

1、解析速度偏慢(应该是正则没有写好)。

2、关于更新语句的处理效果太烂了。

3、很多SQL的运算付没有保留下来。

4、如果需要保留关键的运算付,就使用标记了   "老"   字的代码

列举一些列子:

select state as `status`, round(sum(duration),7) as `duration`, concat(round(sum(duration)/0.002432*100,3), ‘%‘) as `percentage` from information_schema.profiling

最后感言:

1、还有很多情况没有考虑到

2、不知道有没有谁可以推荐C#版的SQL语句解析的工具或者DLL

3、历时3天

这几天心情不好,唉。想回家休息个把月,哈哈

下载连接

http://pan.baidu.com/s/1mglImpU

时间: 2024-12-30 22:33:16

SQL日志分析的一个小工具的相关文章

介绍一个小工具 Linqer

原文:介绍一个小工具 Linqer 这些天写Linq挺烦人的,就上网搜搜可有什么好的sql转Linq的工具,咦,马上就看上了Linqer. 哈哈,介绍一下使用方法吧: 官方下载网站:http://sqltolinq.com/download. 第一步:运行这个神马文件. 第二步:指定一个路径给它.他会生成一个Linqer.exe可运行的文件. 第三步:运行这个exe文件,点击Add按钮, 第四步:在弹出的Add界面中,给串串取个名字(如这里面的Demo),点右边的“省略号”按钮,会弹出你做梦都会

【开源一个小工具】一键将网页内容推送到Kindle

最近工作上稍微闲点,这一周利用下班时间写了一个小工具,其实功能挺简单但也小折腾了会. 工具名称:Simple Send to Kindle Github地址:https://github.com/zhanjindong/SimpleSendToKindle 功能:Windows下一个简单的将网页内容推送到Kindle的工具. 写这个工具的是满足自己的需求.自从买了Kindle paperwhite 2,它就成了我使用率最高的一个电子设备.相信很多Kindle拥有者和我一样都有这样一个需求:就是白

分享一个小工具:UnityRemoteLog

最近经常需要调试Unity客户端的Android版,看LOG是一个最基本的调试方法了.为了看LOG,总要看Eclipse这么重量级的工具,觉得还是有点麻烦,于是抽了点业余时间写了一个小工具:把Unity的LOG使用网络连接转发到一个PC端的窗口程序中. 使用方法 将RemoteLog.cs拷贝到你的Unity Project里面: 在任意一个MonoBehavior脚本的Start()函数中,调用RemoteLog.Instance.Start(主机IP,端口):目前默认端口是2010: 运行U

关于SQL Server镜像的一个小误区

昨天晚上突然接到客户的电话, 说在配置了镜像的生产环境数据库下修改 “已提交读快照” 选项的时候报错, 需要先取消镜像然后再重新搭建.悲催的是这是个近TB的数据库,问我有没有什么快速的方法.于是我就问客户为什么觉得时间长,他说重新搭建镜像的时候要先做完整备份然后再在镜像节点还原这个步骤会花费大量的时间.那么实际需要这么做吗? 在镜像数据库下修改 “已提交读快照” 选项 取消镜像后就会看到镜像节点的数据库的状态 从 “镜像,已同步/正在还原” 变成 “正在还原...”,不要删除它,它还有用. 修改

Java正则表达式——测试正则表达式的一个小工具

正则表达式是一种强大而灵活的文本处理工具.使用它我们能以编程的方式,构造复杂的文本模式,并对输入的字符串进行搜索.一旦找到了匹配这些模式的部分,你就能够随心所欲地对它们进行处理. 关于正则表达式的语法,网上对此有介绍的文章实在是多不胜数,实在找不到,还可以查看Java的API文档,就不多介绍了.这里主要介绍一个可以测试正则表达式的小工具.直接上代码: 1 package com.test.stringregex; 2 //{Args: abcabcabcdefabc "abc+" &q

分享一个小工具:Excel表快速转换成JSON字符串

在游戏项目中一般都需要由策划制作大量的游戏内容,其中很大一部分是使用Excel表来制作的.于是程序就需要把Excel文件转换成程序方便读取的格式. 之前项目使用的Excel表导入工具都是通过Office Excel组件来实现数据访问的,效率十分令人不满.一个端游项目一般要上百个表格,手游项目20.30个表格基本也是要的,于是表格导入程序的过程一般要几分钟,项目后期要接近半个小时. 此次分享的小工具,在速度上有质的飞越,比上述方法实现的工具有接近100倍的速度提升: 完整项目源代码下载:https

x01.TextProc: 两三分钟完成的一个小工具

在工作中,遇到这么个问题,需要将 Excel 表中类似 2134-1234-4456 的商品编号输入到单位的程序中,而程序只认 213412344456 这种没有 ‘-’ 的输入.数量比较多,一笔一笔的敲,费时费力不可取,所以转换一下,复制粘贴,不仅可以提高速度,而且也不易出错.并且,由于 Excel 表是别人提供,可能反复遇到此问题,所以写个转换的小工具是必要的. 直接操作 Excel 吗?问题 ”矮小下“,显然用不着这么麻烦.我的方法是,将商品编号列复制粘贴到记事本中保存为 temp.txt

一个小工具的开发

由于大神们的演讲经常托管在土鳖网上,要想看大神的视频就需要些工具. 从而些了这个小工具,不是很完善,只是能用. 其中比较重要的设计是,由于中美之间的ping很好,掉包也很严重,经常会出现tcp连接不上的情况. 根据这情况,我选择一开始就建立10个tcp连接,将所有的请求分散的到这10个连接上,而不是为每一个socks5的连接建立一个远程连接. 那么怎么标示呢?我选择为每一个socks5连接申请一个ID,这个ID在从fog到princess的传输过程中用来标示相应的socks5连接.从而做到tcp

一个小工具,帮你找到赚钱思路

有时候你知道什么方向赚钱,那么你要入场,该找哪个切入点呢?之前我都是瞎找,从朋友圈或者是公众号大家的推文,找到机会. 前段时间从别处知道了这个工具,我试着搜索了两个词语:副业 和 赚钱 ,得到了这样的一些数据. https://mmbiz.qpic.cn/mmbiz_png/FAlIsKMhcyw9f0aD3xd4AibxuUZond6JpR8kYZsccV6DcOdAML3TSsuwB4aO8Npsmc2PMibH7kXIKDG4JibaEJuCQ/640?wx_fmt=png&tp=webp