2010-06-22 73 views
1

對於我正在編寫的當前應用程序,我選擇將所有數據庫功能放入單個類中,因爲它允許我將數據庫代碼從業務邏輯中分離出來,並且如果我們需要切換到另一個DBMS。然而,最近我的數據庫類已經變得相當大(信息編輯:大約53k),並且由於它的體積,我擔心解析這個文件的速度,因爲它通常必須針對每個請求進行解析。PHP:一個巨型數據庫類或幾個較小的類?

通常在任何給定的時間只有一個或者兩個不同的「類型」的數據庫調用(例如,用戶系統調用,資產系統調用,地圖系統調用,會話系統調用等),因此一個選項我正在考慮將任務分解爲一系列數據庫對象「切片」,然後根據函數請求在運行時動態加載這些任務。另一方面,我擔心這樣做會導致在內存中大量的並行執行(也就是說,每個片現在具有查詢方法,獨立的查詢日誌等)以及強迫我修改所有現有代碼以指向新的較小對象或(b)導致相對性能損失,因爲我在此功能中反向使用已編寫的代碼(例如,使每個切片指向後面到父母的查詢功能以及由於突然使用__呼叫而不是直接訪問方式而導致的性能問題)。

在這種情況下更正確的行動方案是什麼?

編輯更多信息:該文件大約53kb,目前有大約2,350行(並且沒有完成),但這可能會被認爲是傾斜的,因爲我使用擴展的SQL模型來提高可讀性。

SELECT 
    foo, 
    bar, 
    baz 
FROM 
    someTable st 
    LEFT JOIN someOtherTable sot 
     ON st.id = sot.stId 
WHERE 
    cond > otherCond 

有70個查詢功能,每一個執行一些獨特的任務,很少重疊(如果我需要兩個驚人相似的結果集,我可以簡單地忽略什麼,我不需要每次都和重用相同的查詢)。

編輯:實例功能:

public function alarm_getActiveAlarmsByAsset($tier, $id) { 
    if ( !Redacted::checkNumber($tier, $id) 
     || $id < 0 
     || $tier > Redacted::ASSET_LOWEST_TIER 
     || $tier < Redacted::ASSET_TIER_CUSTOMER 
    ) { 
     return false; 
    } 

    $sql = " 
     SELECT 
      alarmId, 
      alarmTime, 
      server, 
      source, 
      reason, 
      train, 
      server_sites.siteId AS `siteId` 
     FROM 
      alarm_alarms 
    "; 

    $join = ''; 

    switch ($tier) { 
     case Redacted::ASSET_TIER_CUSTOMER: 
      $join = ' 
       LEFT JOIN red_campus 
        ON red_campus.campId = red_site.campId 
      '; 
     case Redacted::ASSET_TIER_CAMPUS: 
      $join = ' 
       LEFT JOIN red_site 
        ON red_site.siteId = server_sites.siteId 
      ' . $join; 
     case Redacted::ASSET_TIER_SITE: 
      $join = ' 
       LEFT JOIN server_sites 
        ON server_sites.servId = alarm_alarms.server 
      ' . $join; 
    } 
    $table = isset(self::$dbTierMap[$tier + 1]) ? self::$dbTierMap[$tier + 1]['table'] : 'server_sites'; 
    $field = isset(self::$dbTierMap[$tier + 1]) ? self::$dbTierMap[$tier + 1]['parent'] : 'site'; 
    $sql .= $join . " 
     WHERE 
       ackId IS NULL 
      AND {$table}.{$field}Id = {$id} 
    "; 

    $r = $this->query($sql); 

    if (!$r) { 
     return false; 
    } 

    $alarms = array(); 
    while ($alarm = mysql_fetch_assoc($r)) { 
     $alarms[] = $alarm; 
    } 
    return $alarms; 
} 
+0

「相當大」有多大,並且可能沒有通過更好地重用代碼來優化內部類的可能性? – deceze 2010-06-22 22:59:15

+0

〜53kb,〜2350行,雖然linecount可能會被視爲傾斜,因爲我使用擴展SQL - 將更新後。 – Dereleased 2010-06-22 23:00:41

+0

我是否正確理解,您的應用程序對每個唯一查詢都有單獨的功能? – Mewp 2010-06-22 23:11:46

回答

0

如果您擔心解析時間而不是代碼質量,則可以使用一些編譯器緩存,如APC

但是,如果您有一個大班級,爲了便於閱讀,很可能應該將其重構爲較小的班級。如果你很難找到你需要的東西(例如修改它),那麼它可能太大而無法維護。
如果您決定重構,請記住可維護性和代碼質量遠比執行速度更重要(數據庫I/O比執行代碼慢)。

+0

53k字節不是行,但我明白你在做什麼。在這一點上,一切都很容易找到和處理;我的IDE爲我提供了所有功能入口點的快速鏈接,這些名稱的前綴基於它們所觸摸的系統等。我對您關於APC的「非代碼質量」評論感到好奇,因爲我們可能會採用字節碼緩存;我假設你是指使用APC作爲bandaid而不嘗試重構或修復其他任何東西? – Dereleased 2010-06-22 23:11:07

+0

是的,你的理解是正確的。我的意思是,如果您對代碼感到滿意並且只是想要速度,那麼APC可能就是解決方案。 – Mewp 2010-06-22 23:13:54

0

其難以分辨不知道分貝方案,但它總是更容易保持幾類比一個大的(例如,每個邏輯實體,一類/ db表)

由於對數據庫(和任何網絡請求)的請求總是需要更長的時間,因此您不必擔心解析時間

+0

,我幾乎可以肯定我無所事事,但這是我從中型應用程序升級到高可用性大型應用程序的第一步。 – Dereleased 2010-06-22 23:03:53

+1

如果這是您的第一步,那麼請記住:過早優化是所有邪惡的根源。 – Mewp 2010-06-22 23:08:27

1

通常情況下,維護許多小類更容易。對於MySQL(主要是用PHP使用)中有多個類發電機可供選擇:

sourceforge: PHP Class Generator

sourceforge: php Class Generator - PCG

或許你能在那裏找到新的思路。

+4

在我的愚見中,請**不要使用代碼生成器。使用一個好的庫比生成代碼更好。機器生成的代碼即使可讀,也很快變得無法維護。此外,它嚴重破壞[DRY](http://en.wikipedia.org/wiki/Don%27t_repeat_yourself)。 – Mewp 2010-06-22 23:15:37

4

據我所知,您的數據庫類基本上包含所有可能的查詢,硬編碼,在整個應用程序中?

實現數據庫層抽象的更好方法是將查詢抽象爲內部一致的格式,並使用模型和數據庫適配器將這些查詢變爲實際的SQL。例如:

$customer = $Customer->find(array(
    'fields' => array('name', 'id'), 
    'condition' => array('ssn' => $ssn) 
)); 

Customer類映射到特定的表,並在必要時可以映射模式不同的列:

class Customer extends BaseModel { 
    public $table = 'xe_a3_cstmr'; 
    public $schema = array(
     'name' => 'ze_42_nm', 
     … 
    ); 
} 

的BaseModel原來這些抽象查詢到真實的SQL,這取決於數據庫它需要傾訴:

SELECT `xe_a3_cstmr`.`ze_42_nm`, `xe_a3_cstmr`.`…` FROM `xe_a3_cstmr` 
WHERE `xe_a3_cstmr`.`ssn` = 123235; 

這樣,你的數據庫層將不會與您需要在您的應用程序,使每一個新的查詢成倍增長,同時還維修器材靈活性將查詢映射到不同的數據庫。這就是所謂的ORM。更不用說,這實際上提供了更容易的抽象。不需要重寫每個硬編碼查詢,只需編寫一個不同的數據庫適配器即可。

正如Mewp在評論中提出的那樣,一個好的起點是Doctrine

+0

更準確地說,它包含可能需要構建的每種類型的查詢;有時候這是一個簡單的靜態查詢,有時候查詢是基於相關信息構建的:例如,在可以存在於0至3層的資產意識中,相同的函數將用於生成資產查詢在任何基於手頭桌子的語義知識的層面上;我會在我的帖子中編輯一個例子。 – Dereleased 2010-06-22 23:58:54

+0

我想我現在要用一個字節碼緩存機制;爲了提高效率,我花了很多時間調整查詢,甚至是爲了提高效率而進行的查詢,我有點謹慎將查詢交給查詢生成器。我將會研究這種系統,並可能在未來的日期和時間考慮這個系統,但是現在我對我的最大恐懼是原始性能,我不認爲增加一個新的抽象層是正確的方式解決這個問題。 – Dereleased 2010-06-23 00:16:20

+0

@Dereleased與往常一樣,在性能和靈活性(以及可維護性)之間有一個折衷。 ORM給你難以置信的靈活性,但當然可能會有更糟糕的表現。如果這是您主要關心的問題,那麼構建您自己的查詢可能確實是更好的選擇。無論如何,您可能需要查看它,「日常查詢」可能不會受到很大的性能影響,並且您仍然可以爲困難情況保留專門的手工查詢。查詢生成過程本身可以通過適當的緩存加速,如果這是一個問題。 – deceze 2010-06-23 01:21:30