2008-10-23 59 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

從數據檢索層,標準設計模式是有兩個方法接口,一個是全部的,一個是塊大小。

如果您願意,您可以分層對其進行分頁的組件。