这里有一个理论问题。
我为 ASP.NET 网站制作了一个数据库搜索界面。我使用 linq to sql 进行 BL 操作。我一直在寻找实现高效分页的不同方法,我认为我现在已经找到了最好的方法,但我不确定性能差异到底有多大,并且想知道是否有专家可以给出任何解释/建议?
方法1:我在很多教程中看到的传统方法使用纯linq to sql,并且似乎创建了一种方法来获取数据。然后是一种返回寻呼机计数的方法。我想这可以分组在一个方法中,但本质上结果似乎是创建一个 IQueryable 来保存整个查询的数据,然后执行 IQueryable.Count() 和 IQueryable.Skip().Take() .
我看到一些网站批评这种方法,因为它会导致评估两个查询,这显然不如使用存储过程高效...... 因为无论如何我都使用全文搜索,所以我需要为我的搜索编写一个 SP,因此根据之前的评论,我决定在 SP 中进行分页和计数。所以我得到了:
方法2:从BL调用存储过程。在SP中,WHERE子句根据用户指定的字段组装并创建动态查询。动态查询的结果被插入到带有临时标识键的表变量中,我在该变量上执行 COUNT(*) 和 SELECT WHERE (temp_ID >= x 和 temp_ID < y).
在我看来,这两种方法原则上执行相同的操作......
我想知道方法 2 是否实际上比方法 1 更有效(不管 linq to sql 中不提供全文...)。为什么?增加多少? 据我了解,SP要求查询只生成一次,所以应该更高效。但还有什么其他好处呢?
还有其他方法可以进行高效的分页吗?
我终于开始对此进行一些有限的基准测试。我只在有 500 个条目的数据库上对此进行了测试,因为这是我到目前为止必须提交的内容。
在一种情况下,我使用了动态 SQL 查询
SELECT *, ROW_COUNT() OVER(...) AS RN ... FROM ... WHERE RN BETWEEN @PageSize * @PageCount AND @PageSize * (@PageCount + 1)
在另一个中,我使用完全相同的查询,但没有 ROW_COUNT() AND WHERE ... 子句并执行
db.StoredProcedure.ToList().Skip(PageSize * PageCount).Take(PageSize);
在方法中。
我尝试返回 10 和 100 个项目的数据集,据我所知,所需时间的差异可以忽略不计:存储过程为 0.90 秒,存储过程为 0.89 秒。
我还尝试添加计数方法,就像您想制作寻呼机一样。在存储过程中,这似乎增加了对完整结果集执行第二次选择的非常轻微的开销(从 0.89 秒到 0.92 秒)。这可能会随着数据集的大小而增加。
我添加了对 Linq to SQL 查询的第二次调用,其中包含 .Count(),就像您使用需要 ASP.NET 分页的两种方法时所做的那样,并且这似乎根本不影响执行速度.
考虑到数据量很小,这些测试可能没有多大意义,但这就是我目前使用的数据集。随着要评估的数据集变得更大,您可能会预期 Linq to SQL 的性能会受到影响...