希格工作室

2012年4月7日 星期六

網站效能的追源溯本(Linq)

Linq真好用(廢話)

Linq搭配LinqToxxx or Entity的結合根本好用到不行

用不著寫一堆連線方案,也不用擔心SQL Injection,也不用因為寫SQL語句時,造成的一堆"字"亂七八糟的難維護,甚至連SQL都不用學了。

真是好用的東西

事不宜遲,就來寫個輸入一筆訂單,若存在符合訂單則修改數量,不存在則新增一筆,超過一筆以上則保留數量最多的並刪除其它多餘資料的標準Linq語句吧。



            var dbLink = new db();
            var catchOrder = from o in dbLink.OrderList
                             where o.OrderID == "J001"
                             select o;
            if (catchOrder.Count() == 0)
            {
                var newOrder = new OrderList();
                newOrder.OrderID = "J001";
                newOrder.OrderName = "新訂單01";
                newOrder.Quantity = 10;
                dbLink.OrderList.InsertOnSubmit(newOrder);
            }
            if (catchOrder.Count() == 1)
            {
                foreach (var upd in catchOrder)
                {
                    upd.Quantity = 11;
                }
            }
            if (catchOrder.Count() >= 2)
            {
                var MaxQuantity = catchOrder.Max(m => m.Quantity);
                var delSomeThing = from d in catchOrder
                                   where d < MaxQuantity
                                   select d;
                foreach (var delIt in catchOrder)
                {
                    dbLink.OrderList.DeleteOnSubmit(delIt);
                }
            }
            dbLink.SubmitChanges();


我們姑且不論是什麼情況會有這麼詭異的需求...那不是重點。

基本上類似這樣子的寫法應該很常見,但這語法裡有什麼問題存在?相信應該很容易知道。

Linq因為它是一個你要它做時,它才會動的東西,所以即使你在最開頭寫好了select from....,它並不會做任何事,只是放在那裡,等你找它做事,當只有在count、max....xxx等語句出現或foreach它時,才會與資料做連繫,所以在這一個簡單判斷的語法裡,總共至少需要叫資料庫做至少5~7次以上的動作,會不會太浪費資源了一點?

catchOrder.Count()catchOrder.Max()catchOrder.XXX()太好用了,又容易看懂,如果你覺得這沒什麼,結果瘋狂使用它,去試著想用的人多一點時,會發生什麼事吧?一個人是7次,1000個人就是7千次,千萬不要因為好用而濫用。

     


            var dbLink = new db();
            var catchOrder = from o in dbLink.OrderList
                             where o.OrderID == "J001"
                             select o;
            var bakOrder = catchOrder.ToList();
            int useCount = bakOrder.Count();
            if (useCount == 0)
            {
                var newOrder = new OrderList();
                newOrder.OrderID = "J001";
                newOrder.OrderName = "???01";
                newOrder.Quantity = 10;
                dbLink.OrderList.InsertOnSubmit(newOrder);
            }
            if (useCount == 1)
            {
                foreach (var upd in catchOrder)
                {
                    upd.Quantity = 11;
                }
            }
            if (useCount >= 2)
            {
                var MaxQuantity = bakOrder.Max(m => m.Quantity);
                var delSomeThing = from d in catchOrder
                                   where d < MaxQuantity
                                   select d;
                foreach (var delIt in catchOrder)
                {
                    dbLink.OrderList.DeleteOnSubmit(delIt);
                }
            }
            dbLink.SubmitChanges();

這邊做簡單的調整(但不代表最好,因為更好的有很多,這邊只是減少對資料庫溝通而已)
利用ToList先行將資料取得到記憶體中,接著計取Count保留,若有需要時亦用來計取Max,如此一來對資料庫要求的次數則從最少5~7次降為最少2次,如此便減少與資料庫之間來往,理論上而言效能應是比較好的。(實際情況請依狀況而定)

在撰寫時,最好搭配SQL Profiler瞭解你的Linq到底幹了什麼事。

沒有留言:

張貼留言