2011-03-26 69 views
0

我想優化symfony應用程序與教義。我偶然發現了以下問題:學說嵌套多個連接

在視圖中我使用了$ project-> getProgress();但通過這樣做,查詢數量會隨着項目數量的增加而增加。所以我試圖用左連接將進度放到項目查詢中(重寫findAll方法),但是這並沒有解決。查詢的數量實際上增加了。

public function findAll($hydrationMode = null) 
{ 
    $q = $this->createQuery('p') 
        ->leftJoin('p.progress pr') 
        ->leftJoin('pr.sfGuardUser u') 
        ->leftJoin('p.raws r') 
        ->leftJoin('p.series'); 
    return $q->execute(array(), $hydrationMode); 
} 

這是我試圖用盡可能少的查詢創建結果:

array() { 
    [0]=> 
    array() { 
    ["id"]=> string(1) "1" 
    ... 
    ["progress"]=> 
    array() { 
     array() { 
      array() { progress1 } 
      array() { progress2 } 
      array() { progress3 } 
      .... 
     } 
    } 
    } 

我通過兩個Symfony和學說的文件看,但沒有找到我回答。我也在谷歌上搜索了很長一段時間。 (我幾個月來一直在尋找解決方案)我希望我已經描述了我的問題。

的schema.yml:

projects: 
    actAs: 
    Timestampable: ~ 
    columns: 
    user_id: integer(4) 
    series_id: bigint 
    pages: int 
    chapter: string 
    translators_id: bigint 
    proofreaders_id: bigint 
    cleaners_id: bigint 
    typesetters_id: bigint 
    raws_id: bigint 
    hide_project: bool 
    complete: bool 
    relations: 
    sfGuardUser: 
     local: user_id 
     foreign: id 
     onDelete: CASCADE 
    series: 
     local: series_id 
     foreign: id 
     type: one 
     foreignType: many 
     onDelete: CASCADE 
    progress: 
     local: id 
     foreign: projects_id 
     onDelete: CASCADE 
     type: one 
     foreignType: many 

projectsProgress: 
    actAs: [Timestampable] 
    columns: 
    projects_id: bigint 
    user_id: integer(4) 
    job: 
     type: enum 
     notnull: true 
     values: [tl,pr,cl,ts] 
    beginpage: int 
    endpage: int 
    complete: bool 
    file: string 
    url: clob 
    relations: 
    sfGuardUser: 
     local: user_id 
     foreign: id 
     onDelete: CASCADE 
    projects: 
     local: projects_id 
     foreign: id 
     onDelete: CASCADE 
     foreignAlias: progress 

回答

0

使用水合物模式的問題是您可以獲取不會使用的數據。我真的不知道如何獲取所有數據,但假設每個項目都會添加所有必需的數據,至少還有一個查詢...

對於複雜查詢(和優化),我更喜歡做一個手動查詢,設法將所有需要的數據在一個查詢,例如:

$query = "SELECT ... FROM projects p LEFT JOIN progress pr (LEFT JOIN sfGuardUser u (LEFT JOIN...) ON pr.user_id = u.id) ON p.id = pr.projects_id" 

$rs = Doctrine_Manager::getInstance()->getCurrentConnection()->fetchAssoc($query); 

$ RS與選擇的數據陣列。擁有所有的數據,你可以根據你的喜好製作一個數組,但要記住,這樣你可以做一個查詢(減少數據庫負載),但是添加一些時間機器來解析數組。

+0

我設法通過重寫這樣的代碼來減少100-150ms的加載時間:http://pastebin.com/rS2v2nSF 這是實現它的最好方法還是有更好的方法? – ikore 2011-03-27 16:27:48

+0

我正在閱讀代碼。我們在談論多少個項目?因爲這種方式可以將數據庫負載轉移到解析負載,並且您可能沒有使用所有項目(如果是這樣,請過濾它們)。有時最好多一些查詢,少一些解析,但總是取決於多少數據。例如,您可以執行2個查詢:一個帶來項目數據(if塊),另一個帶來進度和原始數據。優化查詢的方法是減少連接表。檢查http://pastebin.com/svXux2pv – Pabloks 2011-03-27 19:51:52

+0

我見過你的代碼。我們正在討論1到20個開放項目,我需要所有項目,因爲這個頁面是一個列表,顯示每個開放項目的進度。 (忘記添加where條件來過濾完成的)現在頁面的加載時間現在是450ms。我會試着玩你的代碼,有一些需要修復的sql。我會比較兩者之間的加載時間。 – ikore 2011-03-27 20:36:24

0

您需要修改的獲取對象Project包括聯接的查詢。通常情況下,應將提取Project對象的查詢置於ProjectTable中。

如果要修改所有查詢或Project查詢的子集,請查看Doctrine Query Execution Listeners

+0

如果我修改查詢,查詢量從17增加到253,並且進度的子集總是空的。 – ikore 2011-03-27 14:42:30