簡單測試linq to sql性能


     前些日子,做了一個物業收費系統,cs模式,用到了linq to sql 技術,這是我第一次使用這個東東寫程序存取數據庫,迷迷糊糊搞得一塌糊塗,當時有個同學他們找好的分頁組件,然后寫好了調用方法,由於時間比較急,而且第一次用,所以沒有怎么研究就直接按照注釋使用他們寫好的分頁方法,然而開發過程中一直都對他們寫的方法有懷疑,會不會是一種投機取巧,胡編亂造的?后來我也做過一些簡單分析,我發現程序在業務邏輯層中每次都從數據庫中將數據全部讀取出來,然后循環將數據轉成特定的List,也就是遍歷整個數據集合,然后在顯示層中將List進行分頁,最后放到DataGridView中,其中列名自動設定為類的屬性值,剛開始我還一直認為這樣的方法好方便啊,一下子全部生成了,直到程序馬上接近尾聲時,我發現程序的操作日志記錄已經達到了4500條,每次打開日志管理界面時,程序都要加載上半天才能出來,我徹底對linq產生了懷疑,確切的說並不是對linq產生懷疑,而是分頁方法以及程序算法產生了懷疑。
    顯示層的分頁代碼部分:
 1 dataGridView.DataSource = data.Take(pagerControl1.PageSize * pagerControl1.PageIndex).Skip(pagerControl1.PageSize * (pagerControl1.PageIndex - 1)).ToList();,其中data是業務邏輯層獲取到的數據,業務邏輯層:     
 2  
 3  
 4 var data = from d in jx.LogTable
 5                            orderby d.OperTime descending
 6                            where Tflag.Equals("全部") ||
 7                            ((d.OperTime >= t1 && d.OperTime <= t2) && (d.OperName.Contains(content) || d.UserID.Contains(content)))
 8                            select d;
 9                 List<LogTable> items = new List<LogTable>();
10                 foreach (var d in data)
11                 {
12                     LogTable item = new LogTable();
13                     item.編號 = trim(d.ID);
14                     item.事件 = trim(d.OperName);
15                     item.操作員 = trim(d.UserID);
16                     item.標志 = trim(d.mark);
17                     item.操作時間 = trim(d.OperTime);
18                     items.Add(item);
19                 }
20                 return items;

 

此處不僅將所有數據全部讀取出來了,而且還遍歷了一遍,當數據達到4500條時就出現了卡頓現象,情況糟糕程度可想而知,好丑陋的代碼啊,而且程序牽扯到這個的地方簡直多的要命,如果要改動的話,一定是一場災難!
    之前一直在忙,沒有時間去測試程序中所存在的問題以及如何能更高效的使用linq開發應用程序,今天擠出點時間來做了個小小的測試,這讓我重新對linq產生了興趣。
    測試中的數據庫表仍然不改變,還是操作日志表,不同的是我在該表中追加了更多的數據,總記錄數幾乎達到 110萬條,然后對這110萬條數據進行測試。具體測試如下:
    當點擊數據總條數時,彈出數據庫操作日志表的總記錄數,點擊加載數據時,對110萬條數據進行分頁 , 每頁10條,取第三頁的10條數據,點清空數據時,對表格中加載的數據進行清空處理:
    
總條數如下:
 首次運行,點擊加載數據時,共耗時9100毫秒:
 
然后點擊清空數據,再次點擊加載數據時,共耗時2899毫秒:
 
之后重復測試,時間一直保持在3000毫秒左右,也就是3秒鍾,第二次點擊后發現時間明顯加快了,3倍有余,但是我想說的是這個速度還是非常非常慢的,因為表中的數據列所存儲的值很小,沒有什么大的數據,為什么會這么慢呢?看代碼:
            
1 Stopwatch sw = new Stopwatch();
2             sw.Start(); //開始計時
3  
4             var data = (from d in db.Log select d).ToList();//將數據全部查詢出來,並且ToList()
5             dataGridView1.DataSource = data.Skip(20).Take(10).ToList();//分頁
6  
7             sw.Stop();   //計時結束
8             MessageBox.Show("共耗時:"+sw.ElapsedMilliseconds.ToString()+"毫秒"); 
9  

 然后我對代碼做了改變,如下:

1 Stopwatch sw = new Stopwatch();
2 sw.Start(); //開始計時
3 
4 var data = (from d in db.Log select d);//只是寫好了查詢條件,注意此處
5 dataGridView1.DataSource = data.Skip(20).Take(10).ToList();//分頁
6 
7 sw.Stop(); //計時結束
8 MessageBox.Show("共耗時:"+sw.ElapsedMilliseconds.ToString()+"毫秒");

 

其實只是將上邊標紅的地方刪掉了,也就是ToList()部分, 采用控制變量法,其他數據和條件全部不做任何變動,看效果:
首次點擊加載數據時,共耗時185毫秒: 
 
清空后,第二次點擊加載數據時,共耗時39毫秒: 

 
     之后測試,一直保持在40毫秒左右,差距為什么會這么大?
    其實,LINQ執行過程的一個重要特征是延遲加載,就是知道要獲取數據時,才會進行計算。大家可能認為執行完var data = from db.Log select d語句,然后在開始skip,take函數進行分頁,所有的值都會存到data中了,實際上,這條語句會延遲到foreach或者ToList()調用時才會執行。而var data = (from db.Log select d)Skip(20).Take(10);語句執行完之后,程序只是生成了一個比較完美的sql語句等待着執行,直到ToList()或者foreach出現,也就是一直等待程序需要獲取數據時才開始執行數據庫查詢,這就解釋了為什么差距會這么大的問題,同時也說明了linq進行分頁的效率還是非常可以的,在110萬條記錄下進行分頁最多需要大約200毫秒時間,最快大約40毫秒。
    一定要注意:先分頁在獲取,而不是先獲取再分頁! 
    於是,為了測試效率,我將數據追加到了220萬條,重新測試:
    發現首次查詢時,共耗時195毫秒:
清空后,再次查詢,共耗時 37毫秒:

 
     大功告成,經過測試,在linq分頁前不能調用讀取方法,應該分頁后再查詢...看來本次的項目開發可以大膽的繼續使用linq來操作數據庫了。當然,之前的物業管理系統,等忙完這一段時間,我得幫忙改改去,做人得負責任啊!!!

  沒文化真可怕,這么簡單的知識竟然現在才知道!

我的網址是:http://www.yxxrui.cn


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM