如何寫出易調(diào)試的SQL
1.前言
相比高級(jí)語(yǔ)言的調(diào)試如C# , 調(diào)試SQL是件痛苦的事 . 特別是那些上千行的存儲(chǔ)過(guò)程, 更是我等碼農(nóng)的噩夢(mèng).
在將上千行存儲(chǔ)過(guò)程的SQL 分解到 C# 管理后, 也存在調(diào)試的不通暢, 如何讓調(diào)試流暢些呢, 請(qǐng)看后續(xù)
2.常見(jiàn)調(diào)試
2.1 通常在Dapper 里面一個(gè)斷點(diǎn)下去, 抓到類似如下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
各種@符號(hào), 需要手工替換后才能調(diào)試(麻煩), 要是能抓到最終SQL就好了
2.2 慶幸的是可以通過(guò)SQLServer Profiler 來(lái)抓到最終SQL
但是生產(chǎn)環(huán)境中的SQLServer, 并發(fā)執(zhí)行的SQL 非常多, 如上圖所見(jiàn), 在一大堆SQL 里面找到你剛才執(zhí)行的SQL也比較麻煩, 即使可以Ctrl + F 調(diào)出搜索框來(lái)搜索, 也要想個(gè)好的關(guān)鍵字來(lái)搜索 , 麻煩.
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, 就不用煞費(fèi)苦心去抓了.
PS: 有人可能會(huì)質(zhì)疑這樣替換的效率,不用擔(dān)心已測(cè)試 , C#的字符串替換是非??斓? 上面的調(diào)用實(shí)例, 當(dāng)時(shí)的測(cè)試結(jié)果是 微妙和納秒級(jí)別, 有興趣的看管可以再測(cè)試.
4. ***
現(xiàn)在丟給Dapper執(zhí)行的不再是 充滿@參數(shù)的SQL , 而是一個(gè)替換好的最終SQL.
這樣當(dāng)老板隔老遠(yuǎn)吼道你說(shuō): 小蔣, 你tm 有個(gè)XX bug ,趕緊看看.
你可以不慌不忙的在 Dapper Query處打個(gè)斷點(diǎn)
鼠標(biāo)放在SQL變量上, 輕松的拿到最終SQL進(jìn)行調(diào)試, 而不是, 手動(dòng)去替換@參數(shù), 又或則在SQLServer Profiler 里面大海撈針了!!!