2013年2月7日 星期四

[MS SQL]將多筆資料合併欄位,減少不必要的連線

之所以會有這篇文章,是最近在改寫公司老舊的ASP報表

主要的邏輯是撈出全部資料後,逐筆判斷該資料在另一個Table是否有相似的資料

如果有則Response出來,秀在此筆資料的下方,但如此簡單的邏輯,卻要Run很久才能跑出來

仔細看他的寫法是這樣,我以C#改寫,以使用者登入紀錄為例,我建了兩個資料表:


使用者資料表
登入紀錄資料表
1 2

當然這裡舉例的不是那麼恰當,登入紀錄應該是記錄到時分秒單位

重點是在下面這段程式:


string connString = WebConfigurationManager.ConnectionStrings["TestDBconn"].ConnectionString;
SqlConnection conn = new SqlConnection(connString);
SqlCommand cmd = new SqlCommand();
cmd.Connection = conn;

string Sql_User = "select * from [User]";
SqlDataAdapter da = new SqlDataAdapter(Sql_User, conn);
DataTable dt = new DataTable();
da.Fill(dt);
if (dt.Rows.Count > 0)
{
    for (int i = 0; i < dt.Rows.Count; i++)
    {
        //依使用者撈出登入紀錄
        string Sql_Login = "select * from LoginRecord where UserID = " + dt.Rows[i]["sn"].ToString();
        da = new SqlDataAdapter(Sql_Login, conn);
        DataTable dt_login = new DataTable();
        da.Fill(dt_login);
        if (dt_login.Rows.Count > 0)
        {
            for (int k = 0; k < dt_login.Rows.Count; k++)
            {
                /* 
                 * Show Login Data . . . . .
                 */
            }
        }
    }
}

乍看之下結果沒什麼問題,但很可怕的是逐筆連線去執行select

因如果資料可能上千上萬,甚至DB是用 Link Server的方式,

原本連線要兩秒這樣加下來就會Run到天荒地老

接著就會換來使用者的一句,程式怎麼寫那麼爛Q_Q

所以將這支程式做一點改寫,使用SQL的for XML Path語法

3

現在已經把該使用者登入紀錄全篩到一個新的欄位LoginData,

但這樣還是不太好閱讀,故我們用一些小技巧,把它轉為varchar

並用逗號分隔,再用Substring去除開頭的逗號:

4

如此已經完成抓出每個使用者的登入紀錄了,

接下來只要把這個子查詢,加入主表裡就改寫成功了:

5



經過這樣改寫已經把連線此數降為1次,

接下來只需要在程式裡用Split切割逗號,去秀出要的資料,

這種寫法應該是程式老手不太會犯的錯誤,

活生生的案例在實務上遇到了,也許一開始資料量小沒care這麼多

但還是養成code review的習慣以免害到後人阿!

2 則留言: