LINQ To SQL的一點(diǎn)討論
LINQ To SQL分頁(yè)失敗后會(huì)有什么結(jié)果呢?關(guān)于使用LINQ To SQL分頁(yè)有什么需要注意的么?LINQ To SQL分頁(yè)的實(shí)質(zhì)是什么呢?那么本文就向你介紹具體的內(nèi)容。
從微軟發(fā)布Linq To SQL依此,程序員圍繞其與SqlDataAdapter等相比進(jìn)行討論,根據(jù)CSDN上的報(bào)道,LINQ比SqlDataReader落后的速度不超過(guò)10%。更加相信微軟對(duì)Linq性能的分析會(huì)結(jié)合算法和統(tǒng)計(jì)結(jié)果來(lái)比較,對(duì)于linq查詢性能--博客園的黃昕已經(jīng)有所分析。于是產(chǎn)生想實(shí)驗(yàn)一下Linq和SqlDataAdapter等分別在大數(shù)據(jù)量下進(jìn)行分頁(yè)。園子里的Yzl的研究室已經(jīng)對(duì)Linq分頁(yè)可能出現(xiàn)的問(wèn)題提出一種情況。(以下只是實(shí)驗(yàn)過(guò)程并非測(cè)試所以沒(méi)有benchmark).
LINQ To SQL分頁(yè)實(shí)驗(yàn)步驟:LINQ To SQL分頁(yè)之對(duì)于數(shù)據(jù)庫(kù):
數(shù)據(jù)庫(kù)名People;數(shù)據(jù)表名Prof 包括ID Name Age三個(gè)字段;記錄數(shù) 10萬(wàn)條(也許不是很足夠)下面的數(shù)據(jù)庫(kù)代碼并非最佳方案,大家貼一下自己的
- CREATE DATABASE People
- ON
- Primary
- (
- NAME='people',
- FILENAME='D:\people_Data.mdf',
- SIZE=10,
- FILEGROWTH=10%
- )
- LOG ON
- (
- NAME='peoplelog',
- FILENAME='D:\people_Log.ldf',
- SIZE=10,
- FILEGROWTH=10%
- )
- GO
- USE People
- CREATE TABLE Prof
- (
- ID INT IDENTITY(1,1) NOT NULL,
- Name NVARCHAR(100) COLLATE Chinese_PRC_CI_AS NULL ,
- Age INT NULL,
- )
- GO
- SET IDENTITY_INSERT Prof ON
- DECLARE @i INT,@age INT
- SET @i=1
- WHILE @i<=100000
- BEGIN
- SET @age=CAST((RAND()*(100-20)+20)AS INT)
- INSERT INTO Prof(ID,Name,Age)
- VALUES(@i,'Name_'+ CAST(@age AS NVARCHAR),@age)
- SET @i=@i+1
- END
- SET IDENTITY_INSERT Prof OFF
測(cè)試代碼一(SQL部分):
網(wǎng)上已經(jīng)有很多非常好的分頁(yè)算法,各人按照設(shè)計(jì)的需要選擇合適的為好,特別提一下Thin的算法(很簡(jiǎn)潔),測(cè)試中采用了李洪根發(fā)布的其中一種分頁(yè)算法
DivPage
- //省略行參數(shù)設(shè)置和拼接
- string strcmd = "SELECT TOP 20 * " +
- "FROM Prof " +
- "WHERE (ID >" +
- "(SELECT MAX(ID) FROM (
- SELECT TOP 60000 id FROM Prof ORDER BY id) AS T)) ORDER BY ID";
顯示查詢耗時(shí):00:00:00.0322245
測(cè)試代碼二(Linq部分)
Linq To SQL的分頁(yè)主要通過(guò)Skip和Take操作符實(shí)現(xiàn),代碼如下:
- //省去設(shè)置參數(shù)
- //分頁(yè)Skip(PageSize * PageIndex).Take(PageSize)
- PeopleDataContext dc = new PeopleDataContext();
- var query =
- (from p in dc.Prof select p).Skip(60000).Take(20);
然而卻出現(xiàn)異常:此提供程序只支持對(duì)返回實(shí)體或投影(包含所有標(biāo)識(shí)列)的有序查詢使用 Skip(),這種查詢?yōu)閱伪?非聯(lián)接)查詢,或者為 Distinct、Except、Intersect 或Union (非 Concat)操作。第一次遇到這種異常(當(dāng)然很多朋友并不會(huì),而且已經(jīng)看出問(wèn)題所在了),查找Skip的定義
- public static IEnumerable<TSource> Skip<TSource>(
- this IEnumerable<TSource> source,
- int count
- )
此方法通過(guò)使用延遲執(zhí)行實(shí)現(xiàn)。即時(shí)返回值為一個(gè)對(duì)象,該對(duì)象存儲(chǔ)執(zhí)行操作所需的所有信息。只有通過(guò)直接調(diào)用對(duì)象的 GetEnumerator 方法或使用 Visual C# 中的 foreach(或 Visual Basic 中的 For Each)來(lái)枚舉該對(duì)象時(shí),才執(zhí)行此方法表示的查詢。再看一下該查詢生成的SQL代碼:
- SELECT TOP 20 [t0].[ID], [t0].[Name], [t0].[Age]
- FROM [dbo].[Prof] AS [t0]
- WHERE NOT (EXISTS(
- SELECT NULL AS [EMPTY]
- FROM (
- SELECT TOP 60000 [t1].[ID]
- FROM [dbo].[Prof] AS [t1]
- ) AS [t2]
- WHERE [t0].[ID] = [t2].[ID]
- ))
Skip查詢需要數(shù)據(jù)標(biāo)識(shí)列提供查詢的根據(jù),是否可以假設(shè)Skip是通過(guò)標(biāo)識(shí)列的唯一性來(lái)逐一返回對(duì)象的呢?
修改數(shù)據(jù)庫(kù)People表Prof,設(shè)置其ID為主鍵,(上面的數(shù)據(jù)庫(kù)相應(yīng)修改為)
- ALTER TABLE Prof
- ADD CONSTRAINT PK_ID PRIMARY KEY (ID)
- GO
再次運(yùn)行,顯示查詢耗時(shí):00:00:00.0478485
LINQ To SQL分頁(yè)問(wèn)題的提出:
1.為什么兩次查詢的耗時(shí)相差那么大呢?(估計(jì)是個(gè)人機(jī)器以及代碼問(wèn)題:))
2.Skip是否通過(guò)主鍵的唯一性逐次返回查詢對(duì)象?
LINQ To SQL分頁(yè)總結(jié):
SQLServer的執(zhí)行效率是按照語(yǔ)義來(lái)執(zhí)行的,也許Linq在性能上不一定和SQLDataAdapter等完全一樣,但是在開(kāi)發(fā)效率上,我們可以看出Linq的實(shí)現(xiàn)代碼的簡(jiǎn)易性是相對(duì)較好的,只要克服其中的一些問(wèn)題,相信Linq會(huì)為以后的數(shù)據(jù)查詢提供更強(qiáng)大幫助!
LINQ To SQL相關(guān)的內(nèi)容就向你介紹到這里,希望對(duì)你了解和學(xué)習(xí)LINQ To SQL有所幫助。
【編輯推薦】