2011-10-01 65 views
1

我有一个页面将来自两个不同表格的聚集数据组合在一起。我希望并行执行这些查询,以减少延迟,而不必引入可执行这两个操作的存储过程。在没有存储过程的情况下在EF4中执行同时无关的查询?

例如,我现在有这样的:

ViewBag.TotalUsers = DB.Users.Count(); 
ViewBag.TotalPosts = DB.Posts.Count(); 
// Page displays both values but has two trips to the DB server 

我想一个类似于:

var info = DB.Select(db => new { 
    TotalUsers = db.Users.Count(), 
    TotalPosts = db.Posts.Count()); 
// Page displays both values using one trip to DB server. 

会产生这样的

SELECT (SELECT COUNT(*) FROM Users) AS TotalUsers, 
     (SELECT COUNT(*) FROM Posts) AS TotalPosts 

因此查询,我正在寻找一个查询来击中数据库服务器。我不问如何使用并行任务或线程

很显然,我可以创建行程单回来的两个值的存储过程两个单独的查询,但我想避免,如果可能的,因为它更容易纯粹在代码中添加额外的统计信息,而不是不断刷新数据库导入。

我错过了什么吗? EF中有一个很好的模式可以说你想要几个不同的值可以并行取出吗?

+0

我猜测帖子与用户无关? –

+0

对。我只是编制了这两个表名。我的实际是其他东西是不相关的 –

+1

我意识到这并没有真正帮助你,但我认为值得注意的是,NHibernate有一个名为'期货'的概念,它有相同的事情(即多个查询在一个请求中)。 – StanK

回答

0

EF4中似乎还没有好的方法可以做到这一点。你可以:

  1. 使用adrift描述的技术会产生一个稍微尴尬的查询。
  2. 使用ExecuteStoreQuery其中T是您创建的某个虚拟类,其中属性获取器/设置器与查询中列的名称匹配。这种方法的缺点是你不能直接使用你的实体模型,而必须求助于SQL。另外,你必须创建这些虚拟实体。
  3. 使用a MultiQuery class that combines several queries into one。这与Stankin在评论中暗示的NHibernate的未来相似。这是一个小黑客,它似乎并不支持标量值查询(还)。
0

你应该可以用Parallel LINQ(PLINQ)完成你想要的。你可以找到一个介绍here

+0

我很熟悉PLINQ,但这种方法并不像我想的那样优化。我宁愿让EF将我的请求重写为单个查询。我已更新我的问题以反映这一点。 –

1

这将使用单个select声明返回计数,但有一个重要警告。您会注意到EF生成的sql使用cross join s,所以必须有一个表(不一定是您计算的那个表),它保证有行,否则查询将不返回结果。这不是一个理想的解决方案,但我不知道在您的示例中可能生成sql,因为它在外部查询中没有from子句。

下面的代码计算在Adventure Works的数据库AddressesPeople表中的记录,并且依靠StateProvinces至少有1纪录:

var r = from x in StateProvinces.Top("1") 
     let ac = Addresses.Count() 
     let pc = People.Count() 
     select new { AddressCount = ac, PeopleCount = pc }; 

,这是产生的SQL:

SELECT 
     1 AS [C1], 
     [GroupBy1].[A1] AS [C2], 
     [GroupBy2].[A1] AS [C3] 
FROM  
    (
     SELECT TOP (1) [c].[StateProvinceID] AS [StateProvinceID] 
     FROM [Person].[StateProvince] AS [c] 
    ) AS [Limit1] 
CROSS JOIN 
    (
     SELECT COUNT(1) AS [A1] 
     FROM [Person].[Address] AS [Extent2] 
    ) AS [GroupBy1] 
CROSS JOIN 
    (
     SELECT COUNT(1) AS [A1] 
     FROM [Person].[Person] AS [Extent3] 
    ) AS [GroupBy2] 

,并从查询的结果时,它运行在SSMS:

C1   C2   C3 
----------- ----------- ----------- 
1   19614  19972 
+0

感谢您的回答。我已经能够得到类似的东西(在我的例子中,我们使用了一个表格,其中有一列,当前有数据库模式版本的行)。它也做了交叉连接。我开始认为在创建存储过程之外没有很好的解决方案。这种方法的问题是我几乎必须为我的几个视图/页面创建一个sproc来减少延迟。我也尝试了DB.ExecuteStoredQuery,但无法在不创建自定义实体的情况下使其工作。 –

+0

@Jeff Moser,如果替代方案是你必须创建多个存储过程,那么我会考虑使用这种方法,特别是因为你有一张表,你可以使用它将有一个记录。由于您正在交叉连接每个只有一行的子查询,因此我认为交叉连接的性能不会成为问题。 –

相关问题