none
LINQ to SQL 查詢問題 RRS feed

  • 問題

  • 請問各位先進們
    當使用 linq to sql 要製作一個簡易的查詢,
    列如我要找新聞上下架時間在某個區間內的文章,
    或是標題、內文含有某些關鍵字的文章
    我想到的方式如下列部份程式碼所示:
    AllNews()是傳回所有的NewsView為IEnumerable

                IQueryable<NewsView> test = news.AllNews().AsQueryable<NewsView>();

                if (StartDate.HasValue)
                {
                    test = test.Where(o => o.StartDate >= StartDate.Value);
                }

                if (EndDate.HasValue)
                {
                    test = test.Where(o => o.EndDate <= EndDate.Value);
                }

                if (categoryID.HasValue)
                {
                    test = test.Where(o => o.CategoryID == categoryID.Value);
                }

                if (!String.IsNullOrEmpty(_keyWord))
                {
                    test = test.Where(o => o.Title.Contains(_keyWord) || o.Body.Contains(_keyWord));
                }

                return View("Search", test.ToList());

    那我的問題在於,這樣做,實際只會對資料庫做一次查詢對嗎?
    這樣做效能會比兜sql然後.ExecuteQuery()來的差嗎?
    是否在.ToList()之前,都沒有實際對資料庫動作?

    先謝謝各位新進們。

    教育乃百年大計
    2010年2月22日 上午 02:40

解答

  • 你可以用 SQL Profiler 去看看 LINQ 丟了什麼指令給 SQL Server,就會知道它是跑一次還是多次。
    初學不是問題,但用不正確的態度來問問題,那就是很大的問題。
    請不要藉新手之名行小白之實,否則只會讓更多無辜的新手得不到幫助而已。
    如果不知道什麼是小白,請參閱:何謂小白
    • 已標示為解答 CHShen 2010年2月22日 上午 03:31
    2010年2月22日 上午 03:15
    版主

所有回覆

  • 你可以用 SQL Profiler 去看看 LINQ 丟了什麼指令給 SQL Server,就會知道它是跑一次還是多次。
    初學不是問題,但用不正確的態度來問問題,那就是很大的問題。
    請不要藉新手之名行小白之實,否則只會讓更多無辜的新手得不到幫助而已。
    如果不知道什麼是小白,請參閱:何謂小白
    • 已標示為解答 CHShen 2010年2月22日 上午 03:31
    2010年2月22日 上午 03:15
    版主
  • Hi,

    您可以用SQL Profiler 去錄執行的過程, 就可以知道整個處理的過程了.





    微軟技術支援中心 CSS - http://www.dotblogs.com.tw/lolota
    2010年2月22日 上午 03:19
  • 謝謝 小朱版主 以及 Lolota Lee
    由於我是使用 SQL Server 2005 Express 因此沒有 SQL Profiler 可以用,
    所以還真不知道有這麼方便的東西阿,抱歉抱歉...

    剛剛 google 的結果發現有個 Open Source 的產品可以用,
    順便在此分享給各位,
    Profiler for Microsoft SQL Server 2005/2008 Express Edition

    這樣應該不會觸犯版規吧!?

    根據我的測試結果,確實是一次而已,而且是在.ToList()時,才對資料庫進行查詢,
    不過擷取到的sql statement卻沒有where條件,這樣又是另一個問題了...
    我再研究研究...


    教育乃百年大計
    2010年2月22日 上午 04:14
  • 如果你的 AllNews() 是元件提供的方法,那 LINQ 跑的就是對 collection,而不是對 database,對 database 的才會出現 WHERE 指令。
    你可能要檢查 AllNews() 的 SQL 指令。
    初學不是問題,但用不正確的態度來問問題,那就是很大的問題。
    請不要藉新手之名行小白之實,否則只會讓更多無辜的新手得不到幫助而已。
    如果不知道什麼是小白,請參閱:何謂小白
    2010年2月22日 上午 04:44
    版主
  • 目前所有的Linq查詢都是後置式查詢,也就是IQueryable本身只是個紀錄查詢條件的class,而目前的Linq provider都是在轉入記憶體時作為真正的存取點.
    PS:以上Linq to object除外

    所以你的問題
    1.只會做一次查詢動作
    2.如果只有一次查詢則當然一定比ExecuteQuery差,因為多了中間層轉換的動作.並且由linq to sql的linq轉成sql語法通常都是相容性為主,所以可能比自己手動最佳化來得差.但大多數的ORM都有cache機制,所以若是多次查詢則就不一定了.但這得看provider本身的機制與架構.理論上平均都匯差許多,尤其是大量query時.

    2010年2月22日 上午 05:09
  • 如果你的 AllNews() 是元件提供的方法,那 LINQ 跑的就是對 collection,而不是對 database,對 database 的才會出現 WHERE 指令。
    你可能要檢查 AllNews() 的 SQL 指令。
    初學不是問題,但用不正確的態度 來問問題,那就是很大的問題。
    請不要藉新手之名行小白之實,否則只會讓更多無辜的新手得不到幫助而已。
    如果不知道什麼是小白,請參閱:何謂小白
    下面是我取得所有news的方式,
    _NwNewsView 是 System.Data.Linq.Table
    NewsView 則是自訂的 view model

            public IEnumerable<NewsView> AllNews()
            {
                foreach (var item in _NwNewsView)
                {
                    yield return new NewsView(item);
                }
            }

    這樣就變成是把 table 的 data 全部放進 memory,
    然後再對 memory 裡的 collection 做查詢了,是這樣的邏輯對嗎?

    如果是這樣的話,那我就應該把查詢的動作寫在直接對 model 操作的那一層了,
    不應該寫在 Controller ,謝謝小朱版主的說明。

    教育乃百年大計
    2010年2月22日 上午 05:16
  • 是的
    如果是MVC架構,你這段Code是放在Controller沒錯,由Controller更新Model,是正確作法.
    但如果你是要將查詢Query作為function則你可以把IQueryable當作引數帶入function中.而不是為了各種條件做不同的Model.
    2010年2月22日 上午 06:35
  • 好久沒用了.
    我覺得查詢條件是放在View裡面做.
    Model我認為就是資料結構.
    View 就跟資料庫的View是一樣.
    他將多個Model組成你要的呈現.
    也就是Model是放資料.

    View 是以各種角度去解釋Model裡面的資料.
    2010年2月22日 上午 10:07
  • 目前所有的Linq查詢都是後置式查詢,也就是IQueryable本身只是個紀錄查詢條件的class,而目前的Linq provider都是在轉入記憶體時作為真正的存取點.
    PS:以上Linq to object除外

    所以你的問題
    1.只會做一次查詢動作
    2.如果只有一次查詢則當然一定比ExecuteQuery差,因為多了中間層轉換的動作.並且由linq to sql的linq轉成sql語法通常都是相容性為主,所以可能比自己手動最佳化來得差.但大多數的ORM都有cache機制,所以若是多次查詢則就不一定了.但這得看provider本身的機制與架構.理論上平均都匯差許多,尤其是大量query時.


    剛剛看了你的問題後才發現,你的AllNews在程式最前頭...
    所以一開始的程式就已下達sql取回至Collection中,故後續的動作都在Linq to object範圍中處理.
    2010年2月23日 上午 12:15