PIXNET Logo登入

痞客興的部落格

跳到主文

歡迎光臨痞客興(Charles Lin)在痞客邦的小天地,這裡留下的是我做過,我看過,我感興趣的一些文章,記錄備忘也和大家分享.

部落格全站分類:數位生活

  • 相簿
  • 部落格
  • 留言
  • 名片
  • 12月 13 週三 201717:23
  • C#語法比較時間大小三種技巧

C#語法比較時間大小三種技巧
資料來源:
(繼續閱讀...)
文章標籤

痞客興 發表在 痞客邦 留言(0) 人氣(18,718)

  • 個人分類:來玩C#
▲top
  • 9月 01 週五 201711:42
  • [C#] EF性能優化

使用EF的linq查詢之後,建議查看一下生成的sql語句.
只選擇某列或某些列
有些時候,在C#裡寫LINQ雖然看著舒服,但性能不一定好,所以有必要做一些調整。比如這種情況:
我需要知道一篇文章的點擊數,僅此而已,我可能會寫:
context.Post.FirstOrDefault(p => p.Id == postId).Hits;
或者:
context.Post.Find(postId).Hits;
我期待著他們只去資料庫裡篩選Hits這一列的資料,然而,通過SQL Profiler會發現,這兩條語句居然把全部列都給select出來了,訪問Hits的操作實際是在記憶體中進行的。
雖然小表看不出性能問題,但萬一你的表裡有一列是存檔位元組流(byte)的,那這樣的操作可能會很慢,並且消耗額外的網路傳輸,所以不能忽視這個問題。
其實,我只要稍作調整,就能避免這個問題,但會LINQ語句難看一點:
context.Post.Where(p => p.Id == postId).Select(p => p.Hits).FirstOrDefault();
LINQ to SQL最終生成的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一個欄位。
ToList()的問題
其實EF很多時候的性能問題都是關係到查詢執行時機的。我們通常的意圖是,首先建立一個查詢運算式,只是build,而不execute。執行的時機是用到這個運算式結果的時候才去執行。
在公司碼程式的時候,我看到好多同事用EF,寫完查詢喜歡直接調用ToList()方法。有時候這會造成很大的性能問題。因為單純聲明一個linq運算式並不會立即執行SQL查詢,然而一旦在後面加上ToList(),就會立即去執行。如果你只是想根據條件選擇其中一些資料,而非全部的話,那ToList()以後再篩選,就是從記憶體裡執行了,並不是把你的條件轉換成sql的where語句去執行。
var query = from ..... // 建立查詢,但不執行
... 
var result = query.ToList(); // 立即執行查詢
所以,你應當儘量避免從ToList()後的結果中再去查找自己想要的元素。
IQueryable, IEnumerable
在這兩個介面的選擇上,我偏向使用IQueryable。大部分時候這兩個介面在使用上的表現都是一致的,但如果你要做的是一個不確定的查詢,意思是這個查詢運算式不是一次性確定的,對於它的結果可能由別的類來選擇到底select哪些東西,這時候就要用IQueryable。
比如我有一個資料層方法:
public IEnumerable<EdiBlog.Core.Entities.Post> GetAllPost()
{
    return context.Post;
}
很顯然,它會被系統中的其他方法調用,而這些調用者希望得到的結果都各不相同。通常的操作就是再拼一個where語句上去:
var myResult = postDa.GetAllPost().Where(...)
但這時,很不幸的是,where語句中的條件並不是轉換為native sql去執行的,它是在記憶體中篩選的。這是一個比較陰的性能問題。所以文章一開始我就建議大家多用SQL Profiler看看自己的LINQ是怎麼執行的。
如果把返回類型換成IQueryable,那麼你的where語句就可以轉化為SQL執行。
public IQueryable<EdiBlog.Core.Entities.Post> GetAllPost()
{
    return context.Post;
}
關於這兩個介面,在StackOverflow上有一個比較好的帖子,大家可以自己看一下:
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論壇上也有個比較直觀的答案:
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
計算個數,Count()和Count
這個是最容易被坑,也是非常嚴重的一個性能問題。當我們需要統計符合某條件的記錄的條數時,我們希望SQL語句是SELECT COUNT(*) ... 這種形式的。然而下面這個看似很自然的寫法卻會導致不希望的結果:
context.Category.FirstOrDefault(p => p.Name == categoryName).Posts.Count;
它產生的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,然後用這個Category的Id去找它所有的Post,最後做Count的其實是.NET在記憶體裡進行的。這顯然把我們不需要的資訊都給SELECT出來了。我們只需要一個Count,為毛會這麼複雜呢?
回顧第一條我所講過的。不難發現。在FirstOrDefault(...)之後訪問的屬性,都是在記憶體裡進行的。所以,當我們訪問Category.FirstOrDefault(p => p.Name == categoryName)的時候,就生成了第一條SQL語句。緊跟其後的“.Posts”是Category物件的導航屬性,EF會用lazy load去載入這個category所有的post,所以就生成了第二條SQL語句。再緊接其後的Count就自然而然在記憶體裡進行了。
如果要讓代碼儘量去生成LINQ to SQL,有個很簡單的原則,就是儘量用LINQ、Lambda運算式,這樣EF才可能幫我們翻譯。C#裡的Count有兩種。Enumerable.Count()是方法,List.Count是屬性。一旦一個東西變成了List,你再去Count,就必定是在記憶體裡進行的了。
所以,在EF中,要進行Count操作,應該這樣寫:
context.Post.Count(p => p.Categories.Any(q => q.Name == categoryName));
這時,Count()接受了一個lambda運算式,LINQ to SQL就能準確翻譯為“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]
現在性能要明顯好很多~
(繼續閱讀...)
文章標籤

痞客興 發表在 痞客邦 留言(0) 人氣(1,931)

  • 個人分類:來玩C#
▲top
  • 8月 30 週三 201709:57
  • [C#] 圖片檔讀取:非鎖定檔方法 [Image.FromFile 釋放]

content from http://jashliao.pixnet.net/blog/post/223534989
FileStream fs = File.OpenRead(StrDestFilePath); //OpenRead[二進位讀檔]
int filelength = 0;
filelength = (int)fs.Length; //獲得檔長度
Byte[] image = new Byte[filelength]; //建立一個位元組陣列
fs.Read(image, 0, filelength); //按位元組流讀取
System.Drawing.Image result = System.Drawing.Image.FromStream(fs);
fs.Close();
 
(繼續閱讀...)
文章標籤

痞客興 發表在 痞客邦 留言(0) 人氣(567)

  • 個人分類:來玩C#
▲top
  • 8月 29 週二 201715:16
  • [C#] C# 二進位陣列(檔案) 和 Base64字串 互轉

content come from http://jashliao.pixnet.net/blog/post/223529346
using System;
(繼續閱讀...)
文章標籤

痞客興 發表在 痞客邦 留言(0) 人氣(1,971)

  • 個人分類:來玩C#
▲top
  • 8月 24 週四 201709:37
  • [C#] 浮點數四捨五入計算

資料來自於 http://jashliao.pixnet.net/blog/post/223492905-c%23-%E6%B5%AE%E9%BB%9E%E6%95%B8%E5%9B%9B%E6%8D%A8%E4%BA%94%E5%85%A5-%5B-math.round-%5D-%E8%A8%88%E7%AE%97
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
(繼續閱讀...)
文章標籤

痞客興 發表在 痞客邦 留言(0) 人氣(770)

  • 個人分類:來玩C#
▲top
  • 8月 18 週五 201709:28
  • [C#] TCP允許多人連線SERVER和重複開啟的Client

程式碼擷錄自jashliao痞客邦部落格
SERVER
(繼續閱讀...)
文章標籤

痞客興 發表在 痞客邦 留言(0) 人氣(11,149)

  • 個人分類:來玩C#
▲top
  • 8月 04 週五 201711:36
  • [C#] HttpWebRequest 存取 WEB API 不要有Cache的寫法

 文章來自 http://jashliao.pixnet.net/blog/post/223322602-c%23-httpwebrequest-%E5%AD%98%E5%8F%96-web-api-%E4%B8%8D%E8%A6%81%E6%9C%89cache%E7%9A%84%E5%AF%AB%E6%B3%95
片段程式碼:
(繼續閱讀...)
文章標籤

痞客興 發表在 痞客邦 留言(0) 人氣(1,203)

  • 個人分類:來玩C#
▲top
  • 7月 18 週二 201715:15
  • [C#] 幾個常用的取路徑及檔名的方法

string file = @"d:\abc\123.txt"
Path.GetFileNameWithoutExtension(file) 取得檔案名,不包含副檔名,本例得到123
(繼續閱讀...)
文章標籤

痞客興 發表在 痞客邦 留言(0) 人氣(10,095)

  • 個人分類:來玩C#
▲top
  • 4月 06 週四 201716:12
  • [C#] Entity Framework中的DatabaseGenerated屬性

首先我們必須知道的是在EF中,當某一個屬性視為primary key時,如果該屬性類別為int,則生成資料庫時會自動變成自加序號
那如果不是int而是Guid,那就必須你自己給值,或自己設定為自加序號
(繼續閱讀...)
文章標籤

痞客興 發表在 痞客邦 留言(0) 人氣(2,014)

  • 個人分類:來玩C#
▲top
  • 4月 06 週四 201715:19
  • [C#] EntityFramework中的導覽屬性略講

Entity Framework以資料庫的概念來解釋比較容易理解,它會建立不同的class,這個class裡面只會有屬性(使用DTO)
比如下例
(繼續閱讀...)
文章標籤

痞客興 發表在 痞客邦 留言(0) 人氣(740)

  • 個人分類:來玩C#
▲top
12...10»

google本站搜尋

文章分類

toggle 綜合知識 (3)
  • 鄉土靈異 (1)
  • 電的知識 (7)
  • 綜合知識 (143)
toggle WEB應用 (14)
  • ASP.NET (2)
  • 來玩Flash (1)
  • CGI (1)
  • EasyUI (5)
  • 來玩JQM (3)
  • 來玩CSS (5)
  • 來玩HTML (10)
  • 來玩drupal (29)
  • 來玩Nginx (8)
  • 來玩JavaScript (50)
  • WEB應用 (13)
  • 來玩Node.js (5)
  • 來玩PHP (31)
  • 來玩Apache (3)
toggle 資料庫應用 (5)
  • 來玩MSSQL (11)
  • 來玩SQLite (1)
  • 來玩MongoDB (10)
  • 來玩MySQL (21)
  • 來玩SQL Relay (2)
toggle 影音多媒體應用 (5)
  • 影音多媒體應用 (0)
  • 來玩vlc (4)
  • 來玩RED5 (1)
  • 來玩Wowza (1)
  • FFmpeg (1)
toggle 來玩Linux (5)
  • 來玩DHCP (1)
  • 來玩iptables (5)
  • 來玩Memcache (1)
  • 來玩Linux (147)
  • shell (12)
  • 來玩docker (22)
  • 股市知識 (2)
  • 程式設計 (2)
  • 邦邦星3C共和國 (2)
  • 時事記評 (0)
  • 奇人奇事 (3)
  • 手機測試 (1)
  • 個人感想 (3)
  • 外行看文學 (1)
  • 來玩Arduino (1)
  • 健身減肥 (46)
  • 免費資源 (10)
  • 來玩C# (92)
  • C語言的嫩咖行 (15)
  • 雲端應用 (13)
  • 趣味人生 (29)
  • 來起七桃 (6)
  • 來玩英文 (7)
  • 電腦軟體 (9)
  • 來玩JAVA (17)
  • 來玩Android (56)
  • 公司會計 (2)
  • 手機應用 (3)
  • 電腦硬體 (2)
  • 來玩Winodws (48)
  • 來玩Banana pi (9)
  • 網管應用 (21)
  • 來玩git (1)
  • 未分類文章 (1)

FlagCounter

C 組廣告版面

參觀人氣

  • 本日人氣:
  • 累積人氣:

bloggerads

誰來我家

最新文章

  • [docker] 指令docker login及docker logout - 登入登出registry
  • [docker] 指令docker diff - 看目前容器讀寫層做了那些變化
  • [docker] 指令docker commit 或 docker container commit - 使用運行中的容器製作印象檔
  • [docker] 為容器建立 init process,方便回收zombie
  • [docker] 指令 docker inspect 或 docker container inspect - 獲取容器的詳細配置資料
  • [docker] 指令 docker exec - 進入到已啟動的容器操作介面
  • [docker] 設定容器的重啟策略 --restart
  • [docker] 指令 docker container prune - 刪除所有停止的容器
  • [docker] 指令 docker rm 或 docker container rm - 刪除容器
  • [docker] 指令 docker stop 或 docker container stop - 停止容器的運行

shinystat