2008-10-23 60 views
6

我正在设计一个多层数据库驱动的Web应用程序 - SQL关系数据库,用于中间服务层的Java,用于UI的Web。语言并不重要。如何处理来自数据库的巨大结果集

中间服务层执行数据库的实际查询。用户界面仅仅需要特定的数据,并没有任何概念支持数据库。

问题是如何处理大型数据集? UI需要数据,但结果可能很大,可能太大而不适合内存。例如,一个路牌应用程序可能有一个服务层:

StreetSign getStreetSign(int identifier) 
Collection<StreetSign> getStreetSigns(Street street) 
Collection<StreetSign> getStreetSigns(LatLonBox box) 

的UI层要求让所有路牌满足某些条件。根据标准,结果集可能很大。 UI层可能会将结果分成单独的页面(对于浏览器)或将它们全部呈现(服务于Goolge Earth)。潜在的巨大结果集可能是性能和资源问题(内存不足)。

一个解决方案是不返回完全加载的对象(StreetSign对象)。而是返回某种结果集或迭代器,它会延迟加载每个单独的对象。

另一种解决方案是改变服务API返回所请求的数据的一个子集:

Collection<StreetSign> getStreetSigns(LatLonBox box, int pageNumber, int resultsPerPage) 

当然的UI仍然可以要求一个巨大的结果集:

getStreetSigns(box, 1, 1000000000) 

我好奇这种情况下的标准工业设计模式是什么?

+0

`Collection getStreetSigns(Street street)`那是你的问题。尽管应用程序可能不知道它是由数据库支持的,但它应该能够控制它所处理的集合的大小。因此,如果该siz没有固有限制,则应该允许应用程序指定一个:`Collection getStreetSigns(Street street,int maxResults,int firstResult)`。 – 2015-12-20 14:15:03

回答

0

在ASP.NET中,我将使用服务器端分页,其中只检索用户从数据存储请求的数据页面。这与检索整个结果集相反,将其放入内存并根据请求进行分页。

0

JSF或JavaServerFaces具有用于将大型结果集分块到浏览器的小部件。它可以按照您的建议进行参数化。我不会以任何方式将其称为“标准工业设计模式”,但值得一看,看看别人如何解决问题。

1

我想说的是,如果潜在的大型数据集,然后去寻呼路线。

您仍然可以设置您不希望它们超过的MAX。

E.G. SO使用的页面大小为15,30,50 ...

0

当我处理这种类型的问题时,我通常会将发送到浏览器的数据(或瘦客户端/胖客户端,以哪种更适合您的情况为准)因为无论符合某些标准的实际数据总大小如何,只有一小部分在任何UI中都可以真正使用。

我住在微软的世界,所以我的主要环境是ASP.Net与SQL Server。以下是有关寻呼两篇文章(其中提到传呼一些技术通过结果集)可能会有所帮助:

Paging through lots of data efficiently (and in an Ajax way) with ASP.NET 2.0 Efficient Data Paging with the ASP.NET 2.0 DataList Control and ObjectDataSource

,微软近来出货另一种机制是他们的“Dynamic Data”的想法 - 你可能能够检查出这个问题的一些指导,以了解他们如何处理这个问题。

0

我在两种不同的产品上做过类似的事情。在一种情况下,数据源是任选分页 - 对于Java,实现类似于可分页接口:

public interface Pageable 
{ 
    public void setStartIndex(int index); 
    public int getStartIndex(); 
    public int getRowsPerPage() throws Exception; 
    public void setRowsPerPage(int rowsPerPage); 
} 

数据源实现的项目的的get()的另一种方法,和一个分页数据源的实现只是返回当前页面。所以你可以设置你的开始索引,并在你的控制器中获取一个页面。

要考虑的一件事就是缓存你的游标服务器端。对于一个Web应用程序,您必须将其过期,但它们确实会帮助您提高性能。

0

fedora digital repository项目返回带有result-set-id的结果的最大数量。然后通过在随后的查询中询问下一个提供result-set-id的块来获得结果的其余部分。只要您不想在查询之外进行任何搜索或排序,它就可以正常工作。

2

我在这种情况下看到的最常见的模式是某种分页,通常在服务器端完成以减少通过线路发送的信息量。

下面是一个使用表变量(通常速度比临时表),在SQL Server 2000实例连同您的路牌例如:

CREATE PROCEDURE GetPagedStreetSigns 
(
    @Page int = 1, 
    @PageSize int = 10 
) 
AS 
    SET NOCOUNT ON 

    -- This memory-variable table will control paging 
    DECLARE @TempTable TABLE (RowNumber int identity, StreetSignId int) 

    INSERT INTO @TempTable 
    (
    StreetSignId 
) 
    SELECT [Id] 
    FROM StreetSign 
    ORDER BY [Id] 

    -- select only those rows belonging to the requested page 
    SELECT SS.* 
    FROM StreetSign SS 
     INNER JOIN @TempTable TT ON TT.StreetSignId = SS.[Id] 
    WHERE TT.RowNumber BETWEEN ((@Page - 1) * @PageSize + 1) 
         AND (@Page * @PageSize) 

在SQL Server 2005中,你可以得到更多的聪明与像普通的东西表格表达式和新的SQL排名函数。但总的主题是,您使用服务器仅返回属于当前页面的信息。

请注意,如果您允许最终用户对他/她所看到的数据应用即时过滤器,则此方法可能会变得混乱。

6

的第一个问题应该是:

¿用户需要,或有能力,管理这个数据量?

虽然结果集应该被分页,但如果它的可能大小太大,答案将是“可能不是”,因此UI不应该尝试显示它。

我在医疗保健系统的J2EE项目上工作,处理大量存储的数据,字面上数百万患者,访问,表单等,一般规则是不显示超过100行或200行用户搜索,建议用户这些标准集产生更多他可以理解的信息。

不同项目之间的实现方式不同,可以强制UI在启动之前向服务层询问查询的大小,或者可以从服务层中抛出Exception if结果集增长过多(但这种方式将服务层与UI的有限实现结合在一起)。

小心!这并不意味着如果服务层上的每个方法的结果大小超过100,都必须抛出异常,这个通用规则仅适用于直接显示给用户的结果集,这是将控件放置在UI中的更好理由而不是服务层。

1

当你像自己一样使用自行生成的行包装类时,需要谨慎的一件事就是在没有你(开发人员)意识到的情况下对数据库进行额外调用的代码。例如,您可能会调用一个返回Person对象集合的方法,并认为引擎盖下的唯一事情是单个“SELECT * FROM PERSONS”调用。实际上,您调用的方法可能会遍历返回的Person对象集合,并进行额外的DB调用来填充每个Person的Orders集合。

正如你所说,你的一个解决方案是不返回完全加载的对象,所以你可能知道这个潜在的问题。我倾向于避免使用行包装的原因之一是它们总是难以调整应用程序并最大限度地减少数据库流量的大小和频率。

0

从数据检索层,标准设计模式是有两个方法接口,一个是全部的,一个是块大小。

如果您愿意,您可以分层对其进行分页的组件。