<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      使用EF框架的優(yōu)化(四)

      EF容易忽略的優(yōu)化點(diǎn)-能轉(zhuǎn)換成SQL執(zhí)行的,不要在內(nèi)存中執(zhí)行,否則,性能很差!

      只選擇某列或某些列

      有些時(shí)候,在C#里寫LINQ雖然看著舒服,但性能不一定好,所以有必要做一些調(diào)整。比如這種情況:
      我需要知道一篇文章的點(diǎn)擊數(shù),僅此而已,我可能會(huì)寫:

      context.Post.FirstOrDefault(p => p.Id == postId).Hits;

      或者:

      context.Post.Find(postId).Hits;

      我期待著他們只去數(shù)據(jù)庫里篩選Hits這一列的數(shù)據(jù),然而,通過SQL Profiler會(huì)發(fā)現(xiàn),這兩條語句居然把全部列都給select出來了,訪問Hits的操作實(shí)際是在內(nèi)存中進(jìn)行的。
      雖然小表看不出性能問題,但萬一你的表里有一列是存文件字節(jié)流(byte)的,那這樣的操作可能會(huì)很慢,并且消耗額外的網(wǎng)絡(luò)傳輸,所以不能忽視這個(gè)問題。
      其實(shí),我只要稍作調(diào)整,就能避免這個(gè)問題,但會(huì)LINQ語句難看一點(diǎn):

      context.Post.Where(p => p.Id == postId).Select(p => p.Hits).FirstOrDefault();

      最終生成的native sql是這樣的:

      exec sp_executesql N'SELECT TOP (1) [Extent1].[Hits] AS [Hits]FROM [dbo].[Post] AS [Extent1]WHERE [Extent1].[Id] = @p__linq__0',N'@p__linq__0 uniqueidentifier',@p__linq__0='850C3A86-6C3D-408B-8099-61EDA559F804'

      真正的只select了Hits一個(gè)字段

      ToList()的問題

      其實(shí)EF很多時(shí)候的性能問題都是關(guān)系到查詢執(zhí)行時(shí)機(jī)的。我們通常的意圖是,首先建立一個(gè)查詢表達(dá)式,只是build,而不execute。執(zhí)行的時(shí)機(jī)是用到這個(gè)表達(dá)式結(jié)果的時(shí)候才去執(zhí)行
      在公司碼程序的時(shí)候,寫完查詢喜歡直接調(diào)用ToList()方法。有時(shí)候這會(huì)造成很大的性能問題。因?yàn)閱渭兟暶饕粋€(gè)linq表達(dá)式并不會(huì)立即執(zhí)行SQL查詢,然而一旦在后面加上ToList(),就會(huì)立即去執(zhí)行。如果你只是想根據(jù)條件選擇其中一些數(shù)據(jù),而非全部的話,那ToList()以后再篩選,就是從內(nèi)存里執(zhí)行了,并不是把你的條件轉(zhuǎn)換成sql的where語句去執(zhí)行。

      var query = from ..... // 建立查詢,但不執(zhí)行 
      var result = query.ToList(); // 立即執(zhí)行查詢

      所以,你應(yīng)當(dāng)盡量避免從ToList()后的結(jié)果中再去查找自己想要的元素。

      IQueryable, IEnumerable

      在這兩個(gè)接口的選擇上,我偏向使用IQueryable。大部分時(shí)候這兩個(gè)接口在使用上的表現(xiàn)都是一致的,但如果你要做的是一個(gè)不確定的查詢,意思是這個(gè)查詢表達(dá)式不是一次性確定的,對(duì)于它的結(jié)果可能由別的類來選擇到底select哪些東西,這時(shí)候就要用IQueryable。
      比如我有一個(gè)數(shù)據(jù)層方法:

      public IEnumerable<EdiBlog.Core.Entities.Post> GetAllPost()
      {
          return context.Post;
      }

      很顯然,它會(huì)被系統(tǒng)中的其他方法調(diào)用,而這些調(diào)用者希望得到的結(jié)果都各不相同。通常的操作就是再拼一個(gè)where語句上去:

      var myResult = postDa.GetAllPost().Where(...)

      但這時(shí),很不幸的是,where語句中的條件并不是轉(zhuǎn)換為native sql去執(zhí)行的,它是在內(nèi)存中篩選的。這是一個(gè)比較陰的性能問題。所以文章一開始我就建議大家多用SQL Profiler看看自己的LINQ是怎么執(zhí)行的。
      如果把返回類型換成IQueryable,那么你的where語句就可以轉(zhuǎn)化為SQL執(zhí)行建議自己實(shí)踐一下!!!

      public IQueryable<EdiBlog.Core.Entities.Post> GetAllPost()
      {
          return context.Post;
      }

      關(guān)于這兩個(gè)接口,在StackOverflow上有一個(gè)比較好的帖子,大家可以自己看一下:
      http://stackoverflow.com/questions/252785/what-is-the-difference-between-iqueryablet-and-ienumerablet
      “IEnumerable: IEnumerable is best suitable for working with in-memory collection. IEnumerable doesn’t move between items, it is forward only collection.
      IQueryable: IQueryable best suits for remote data source, like a database or web service. IQueryable is a very powerful feature that enables a variety of interesting deferred execution scenarios (like paging and composition based queries).”
      在MSDN論壇上也有個(gè)比較直觀的答案:
      IQueryable returns a "queryable" that is a query you could still be enriched before really sending it to the server.
      IEnumerable returns a list that is the actual querying took place and you get the results. ToList is isued to force running the query and returning these enumerable results...
      So in short :
      - use IQueryable if you want to return a base query that could be further enhanced before running it server side (by enumerating its items)..
      - use IEnumerable/ToList if you want to return a list that has been retrieved from the db

      IQueryable返回一個(gè)“queryable”,這是一個(gè)在真正將其發(fā)送到服務(wù)器之前仍然可以豐富的查詢。
      IEnumerable返回一個(gè)列表,該列表是實(shí)際進(jìn)行的查詢,您將獲得結(jié)果。ToList用于強(qiáng)制運(yùn)行查詢并返回這些可枚舉的結(jié)果。。。
      簡(jiǎn)而言之:
      -如果要返回基本查詢,則使用IQueryable,該基本查詢可以在服務(wù)器端運(yùn)行(通過枚舉其項(xiàng))之前得到進(jìn)一步增強(qiáng)。。
      -如果要返回從數(shù)據(jù)庫檢索到的列表,請(qǐng)使用IEnumerable/ToList

      計(jì)算個(gè)數(shù),Count()和Count

      這個(gè)是最容易被坑,也是非常嚴(yán)重的一個(gè)性能問題。當(dāng)我們需要統(tǒng)計(jì)符合某條件的記錄的條數(shù)時(shí),我們希望SQL語句是SELECT COUNT(*) ... 這種形式的。然而下面這個(gè)看似很自然的寫法卻會(huì)導(dǎo)致不希望的結(jié)果:

      context.Category.FirstOrDefault(p => p.Name == categoryName).Posts.Count;

      這是用來統(tǒng)計(jì)某分類下文章數(shù)目的語句,當(dāng)然,因?yàn)榘l(fā)現(xiàn)性能問題,現(xiàn)在已經(jīng)不是這么寫了。它產(chǎn)生的SQL并不是SELECT COUNT,而是分成2條。下面是SQL Profiler抓到的:

      exec sp_executesql N'SELECT TOP (1) [Extent1].[Id] AS [Id], [Extent1].[Name] AS [Name], [Extent1].[DisplayName] AS [DisplayName]FROM [dbo].[Category] AS [Extent1]WHERE [Extent1].[Name] = @p__linq__0',N'@p__linq__0 nvarchar(4000)',@p__linq__0=N'ASPNET'exec sp_executesql N'SELECT [Extent2].[Id] AS [Id], [Extent2].[Title] AS [Title], [Extent2].[Slug] AS [Slug], [Extent2].[PubDate] AS [PubDate], [Extent2].[PostContent] AS [PostContent], [Extent2].[Author] AS [Author], [Extent2].[CommentEnabled] AS [CommentEnabled], [Extent2].[IsPublished] AS [IsPublished], [Extent2].[Hits] AS [Hits], [Extent2].[Rators] AS [Rators], [Extent2].[Rating] AS [Rating], [Extent2].[ExposedToSiteMap] AS [ExposedToSiteMap], [Extent2].[DisplayFrom] AS [DisplayFrom], [Extent2].[DisplayTill] AS [DisplayTill], [Extent2].[LastModifyOn] AS [LastModifyOn], [Extent2].[PublishToRss] AS [PublishToRss]FROM  [dbo].[PostCategory] AS [Extent1]INNER JOIN [dbo].[Post] AS [Extent2] ON [Extent1].[PostId] = [Extent2].[Id]WHERE [Extent1].[CategoryId] = @EntityKeyValue1',N'@EntityKeyValue1 uniqueidentifier',@EntityKeyValue1='3FEB11A2-6E36-4DCE-8C02-614BEF7ACC62'

      可以看到,EF做了兩件事,第一件事是查找Name為"ASPNET"的Category,然后用這個(gè)Category的Id去找它所有的Post,最后做Count的其實(shí)是.NET在內(nèi)存里進(jìn)行的。這顯然把我們不需要的信息都給SELECT出來了。我們只需要一個(gè)Count,為毛會(huì)這么復(fù)雜呢?
      回顧第一條我所講過的。不難發(fā)現(xiàn)。在FirstOrDefault(...)之后訪問的屬性,都是在內(nèi)存里進(jìn)行的。所以,當(dāng)我們?cè)L問Category.FirstOrDefault(p => p.Name == categoryName)的時(shí)候,就生成了第一條SQL語句。緊跟其后的“.Posts”是Category對(duì)象的導(dǎo)航屬性,EF會(huì)用lazy load去加載這個(gè)category所有的post,所以就生成了第二條SQL語句。再緊接其后的Count就自然而然在內(nèi)存里進(jìn)行了。
      如果要讓代碼盡量去生成LINQ to SQL,有個(gè)很簡(jiǎn)單的原則,就是盡量用LINQ、Lambda表達(dá)式,這樣EF才可能幫我們翻譯。C#里的Count有兩種。Enumerable.Count()是方法,List.Count是屬性。一旦一個(gè)東西變成了List,你再去Count,就必定是在內(nèi)存里進(jìn)行的了。
      所以,在EF中,要進(jìn)行Count操作,應(yīng)該這樣寫:

      context.Post.Count(p => p.Categories.Any(q => q.Name == categoryName));

      這時(shí),Count()接受了一個(gè)lambda表達(dá)式,LINQ to SQL就能準(zhǔn)確翻譯為“SELECT COUNT”了:

      SELECT [GroupBy1].[A1]  AS [C1]
      FROM   (
                 SELECT COUNT(1)      AS [A1]
                 FROM   [dbo].[Post]  AS [Extent1]
                 WHERE  EXISTS (
                            SELECT 1 AS [C1]
                            FROM   [dbo].[PostCategory] AS [Extent2]
                                   INNER JOIN [dbo].[Category] AS [Extent3]
                                        ON  [Extent3].[Id] = [Extent2].[CategoryId]
                            WHERE  ([Extent1].[Id] = [Extent2].[PostId])
                                   AND ([Extent3].[Name] = 'ASPNET')
                        )
             )                AS [GroupBy1]

      現(xiàn)在性能要明顯好很多~

      .NET編程委提醒您:ORM千萬種,EF最方便,使用不規(guī)范,性能兩行淚

      posted @ 2024-04-30 15:37  IT苦行僧-QF  閱讀(59)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 亚洲人成电影网站 久久影视| 国产精品小粉嫩在线观看| 白色丝袜国产在线视频| 最新国产精品精品视频| 伊人成色综合人夜夜久久| 少妇人妻偷人免费观看| 国产精品无码免费播放| 亚洲男人的天堂久久香蕉| 国产av综合色高清自拍| 韩国av无码| 国产精品自拍中文字幕| 久久精品丝袜高跟鞋| 亚洲人成网站免费播放| 宝应县| 亚洲欧美不卡视频在线播放| 鲁丝片一区二区三区免费| 无码少妇一区二区三区免费| 色婷婷日日躁夜夜躁| 日本精品一区二区不卡| 欧美性xxxxx极品少妇| 精品久久精品久久精品久久| 少妇人妻偷人免费观看| 久久se精品一区精品二区| 日韩乱码人妻无码系列中文字幕| 黑森林福利视频导航| 99久久久国产精品免费蜜臀| 国产乱码日产乱码精品精| 亚洲欧美日韩在线码| 使劲快高潮了国语对白在线| 亚洲www永久成人网站| 中文字幕国产在线精品| 欧美一区二区三区性视频| 久久精品国产午夜福利伦理| 亚洲精品日韩在线观看| 日本黄页网站免费大全| 国产精品无遮挡猛进猛出| 精品视频不卡免费观看| 绿春县| 久久精品国产亚洲精品色婷婷 | 亚洲日本精品一区二区| 国产95在线 | 欧美|