Linq To SQL分页失败后引发的思考

时间:2022-03-08 08:08:12
前言:
从微软发布Linq To SQL依此,程序员围绕其与SqlDataAdapter等相比进行讨论,根据CSDN上的报道,LINQ比SqlDataReader落后的速度不超过10%。更加相信微软对Linq性能的分析会结合算法和统计结果来比较,对于linq查询性能--博客园的黄昕已经有所分析。于是产生想实验一下Linq和SqlDataAdapter等分别在大数据量下进行分页。园子里的Yzl的研究室已经对Linq分页可能出现的问题提出一种情况。(以下只是实验过程并非测试所以没有benchmark).

实验步骤:
一、数据库
数据库名People
数据表名Prof 包括ID Name Age三个字段
记录数 10万条(也许不是很足够)
下面的数据库代码并非最佳方案,大家贴一下自己的
Linq To SQL分页失败后引发的思考Linq To SQL分页失败后引发的思考
Linq To SQL分页失败后引发的思考CREATE DATABASE People
Linq To SQL分页失败后引发的思考ON
Linq To SQL分页失败后引发的思考Primary
Linq To SQL分页失败后引发的思考(
Linq To SQL分页失败后引发的思考    NAME
='people',
Linq To SQL分页失败后引发的思考    FILENAME
='D:\people_Data.mdf',
Linq To SQL分页失败后引发的思考    SIZE
=10,
Linq To SQL分页失败后引发的思考    FILEGROWTH
=10%
Linq To SQL分页失败后引发的思考)
Linq To SQL分页失败后引发的思考
Linq To SQL分页失败后引发的思考LOG ON
Linq To SQL分页失败后引发的思考(
Linq To SQL分页失败后引发的思考    NAME
='peoplelog',
Linq To SQL分页失败后引发的思考    FILENAME
='D:\people_Log.ldf',
Linq To SQL分页失败后引发的思考    SIZE
=10,
Linq To SQL分页失败后引发的思考    FILEGROWTH
=10%
Linq To SQL分页失败后引发的思考)
Linq To SQL分页失败后引发的思考GO
Linq To SQL分页失败后引发的思考USE People
Linq To SQL分页失败后引发的思考CREATE TABLE Prof
Linq To SQL分页失败后引发的思考(
Linq To SQL分页失败后引发的思考    ID INT IDENTITY(
1,1) NOT NULL,
Linq To SQL分页失败后引发的思考    Name NVARCHAR(
100) COLLATE Chinese_PRC_CI_AS NULL ,
Linq To SQL分页失败后引发的思考    Age INT NULL,
Linq To SQL分页失败后引发的思考)
Linq To SQL分页失败后引发的思考
Linq To SQL分页失败后引发的思考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

测试代码一(SQL部分):
网上已经有很多非常好的分页算法,各人按照设计的需要选择合适的为好,特别提一下 Thin的算法(很简洁),测试中采用了 李洪根发布的其中一种分页算法
Linq To SQL分页失败后引发的思考Linq To SQL分页失败后引发的思考
Linq To SQL分页失败后引发的思考//省略行参数设置和拼接
Linq To SQL分页失败后引发的思考
string strcmd = "SELECT TOP 20 * " +
Linq To SQL分页失败后引发的思考                
"FROM Prof " +
Linq To SQL分页失败后引发的思考                
"WHERE (ID >" +
Linq To SQL分页失败后引发的思考                
"(SELECT MAX(ID) FROM (SELECT TOP 60000 id FROM Prof ORDER BY id) AS T))  ORDER BY ID";
Linq To SQL分页失败后引发的思考
显示查询耗时:00:00:00.0322245

测试代码二(Linq部分)
Linq To SQL的分页主要通过Skip和Take操作符实现,代码如下:
Linq To SQL分页失败后引发的思考Linq To SQL分页失败后引发的思考
Linq To SQL分页失败后引发的思考//省去设置参数
Linq To SQL分页失败后引发的思考
//分页Skip(PageSize * PageIndex).Take(PageSize)
Linq To SQL分页失败后引发的思考
PeopleDataContext dc = new PeopleDataContext();
Linq To SQL分页失败后引发的思考var query 
= (from p in dc.Prof select p).Skip(60000).Take(20);
然而却出现异常: Linq To SQL分页失败后引发的思考此提供程序只支持对返回实体或投影(包含所有标识列)的有序查询使用 Skip(),这种查询为单表(非联接)查询,或者为 Distinct、Except、Intersect 或 Union (非 Concat)操作。 第一次遇到这种异常(当然很多朋友并不会,而且已经看出问题所在了),查找Skip的定义 Linq To SQL分页失败后引发的思考public static IEnumerable<TSource> Skip<TSource>(
Linq To SQL分页失败后引发的思考    
this IEnumerable<TSource> source,
Linq To SQL分页失败后引发的思考    
int count
Linq To SQL分页失败后引发的思考)
Linq To SQL分页失败后引发的思考此方法通过使用延迟执行实现。即时返回值为一个对象,该对象存储执行操作所需的所有信息。只有通过直接调用对象的 GetEnumerator 方法或使用 Visual C# 中的 foreach(或 Visual Basic 中的 For Each)来枚举该对象时,才执行此方法表示的查询。
再看一下该查询生成的SQL代码: Linq To SQL分页失败后引发的思考SELECT TOP 20 [t0].[ID], [t0].[Name], [t0].[Age]
Linq To SQL分页失败后引发的思考FROM [dbo].[Prof] AS [t0]
Linq To SQL分页失败后引发的思考WHERE NOT (EXISTS(
Linq To SQL分页失败后引发的思考    SELECT NULL AS [EMPTY]
Linq To SQL分页失败后引发的思考    FROM (
Linq To SQL分页失败后引发的思考        SELECT TOP 
60000 [t1].[ID]
Linq To SQL分页失败后引发的思考        FROM [dbo].[Prof] AS [t1]
Linq To SQL分页失败后引发的思考        ) AS [t2]
Linq To SQL分页失败后引发的思考    WHERE [t0].[ID] 
= [t2].[ID]
Linq To SQL分页失败后引发的思考    ))
Skip查询需要数据标识列提供查询的根据,是否可以假设Skip是通过标识列的唯一性来逐一返回对象的呢?
修改数据库People表Prof,设置其ID为主键,(上面的数据库相应修改为)
 ALTER TABLE Prof
Linq To SQL分页失败后引发的思考ADD CONSTRAINT PK_ID PRIMARY KEY (ID)
Linq To SQL分页失败后引发的思考GO

再次运行,显示查询耗时:00:00:00.0478485

问题:
1.为什么两次查询的耗时相差那么大呢?(估计是个人机器以及代码问题:))
2.Skip是否通过主键的唯一性逐次返回查询对象?
总结:
SQLServer的执行效率是按照语义来执行的,也许Linq在性能上不一定和SQLDataAdapter等完全一样,但是在开发效率上,我们可以看出Linq的实现代码的简易性是相对较好的,只要克服其中的一些问题,相信Linq会为以后的数据查询提供更强大帮助!

备注:
Scott写了一系列Linq的介绍非常经典
王磊发表的文章中提到过了大量数据分页的实现,主要用的数据库为Northwind而相应的代码也完善。
Linq性能测试[url]http://www.mbeller.de/2007/12/performance-comparison-between-linq.html[/url]

本文出自 “痛而后能善无惧于闯” 博客,请务必保留此出处http://greater.blog.51cto.com/319488/89678