如何寫出易調(diào)試的SQL
1.前言
相比高級語言的調(diào)試如C# , 調(diào)試SQL是件痛苦的事 . 特別是那些上千行的存儲過程, 更是我等碼農(nóng)的噩夢.
在將上千行存儲過程的SQL 分解到 C# 管理后, 也存在調(diào)試的不通暢, 如何讓調(diào)試流暢些呢, 請看后續(xù)
2.常見調(diào)試
2.1 通常在Dapper 里面一個斷點下去, 抓到類似如下SQL:
- SELECT
- a.*
- FROM dbo.ptype a
- INNER JOIN dbo.PType_Price b ON a.typeId=b.PTypeID
- LEFT JOIN dbo.PType_Units c ON a.typeId=c.UnitsId
- WHERE a.typeId=@typeid AND a.CreateDate=@Area
- AND preprice1=@preprice1 AND deleted=@deleted
各種@符號, 需要手工替換后才能調(diào)試(麻煩), 要是能抓到最終SQL就好了
2.2 慶幸的是可以通過SQLServer Profiler 來抓到最終SQL
但是生產(chǎn)環(huán)境中的SQLServer, 并發(fā)執(zhí)行的SQL 非常多, 如上圖所見, 在一大堆SQL 里面找到你剛才執(zhí)行的SQL也比較麻煩, 即使可以Ctrl + F 調(diào)出搜索框來搜索, 也要想個好的關(guān)鍵字來搜索 , 麻煩.
3.解決方案
既然我們想要最終的SQL , 為毛不在丟給Dapper 執(zhí)行前, 就已經(jīng)是最終SQL了呢, 上工具代碼:
- public class SqlHelper
- {
- public Dictionary<string, object> Param = new Dictionary<string, object>();
- public string ReplaceParam(ref string sql)
- {
- if (Param.Count == 0)
- {
- return sql;
- }
- StringBuilder sb = new StringBuilder();
- sb.Append(sql);
- foreach (var item in Param)
- {
- var paramName = item.Key;
- var paramValue = item.Value;
- var type = paramValue.GetType();
- if (type == typeof(string) || type == typeof(DateTime))
- {
- //字符串
- sb.Replace($"@{paramName}", $"'{paramValue}'");
- }
- else if (type == typeof(bool))
- {
- //bool 類型
- if (paramValue.ToString() == "True")
- {
- sb.Replace($"@{paramName}", "1");
- }
- else
- {
- sb.Replace($"@{paramName}", "0");
- }
- }
- else
- {
- //數(shù)值
- sb.Replace($"@{paramName}", paramValue.ToString());
- }
- }
- sql = sb.ToString();
- return sql;
- }
- }
調(diào)用示例:
- public IEnumerable<Ptype> GetPtypeDetail()
- {
- var sql = @"
- SELECT a.*
- FROM dbo.ptype a
- INNER JOIN dbo.PType_Price b ON a.typeId=b.PTypeID
- LEFT JOIN dbo.PType_Units c ON a.typeId=c.UnitsId
- WHERE a.typeId=@Typeid AND a.CreateDate=@CreateDate
- AND preprice1=@preprice1 AND deleted=@deleted
- ";
- var sqlHelper = new SqlHelper();
- sqlHelper.Param.Add("Typeid", "001");
- sqlHelper.Param.Add("CreateDate", DateTime.Now);
- sqlHelper.Param.Add("preprice1", 3.62M);
- sqlHelper.Param.Add("deleted", true);
- sqlHelper.ReplaceParam(ref sql);
- IEnumerable<Ptype> plist = new List<Ptype>();
- using (var con = SQLServerHelper.GetConnection())
- {
- plist = con.Query<Ptype>(sql);
- }
- return plist;
- }
這樣丟給Dapper 執(zhí)行的SQL 始終是最終SQL, 就不用煞費苦心去抓了.
PS: 有人可能會質(zhì)疑這樣替換的效率,不用擔心已測試 , C#的字符串替換是非??斓? 上面的調(diào)用實例, 當時的測試結(jié)果是 微妙和納秒級別, 有興趣的看管可以再測試.
4. ***
現(xiàn)在丟給Dapper執(zhí)行的不再是 充滿@參數(shù)的SQL , 而是一個替換好的最終SQL.
這樣當老板隔老遠吼道你說: 小蔣, 你tm 有個XX bug ,趕緊看看.
你可以不慌不忙的在 Dapper Query處打個斷點
鼠標放在SQL變量上, 輕松的拿到最終SQL進行調(diào)試, 而不是, 手動去替換@參數(shù), 又或則在SQLServer Profiler 里面大海撈針了!!!