2013-07-09 103 views
0

我有一個網站頁面,在加載時,針對具有150,000,000行的表激發10個不同的查詢。避免對頁面重新加載多個SQL查詢

通常,在不到2秒鐘的網頁加載 - 但如果我刷新過於頻繁,它通過長達10秒創造了很多的查詢,其緩慢的頁面加載時間。

如何避免觸發所有這些查詢,因爲它會殺死我的數據庫?

我還沒有緩存。該網站的工作方式如下。我有一個表是所有的URI都存儲。如果用戶輸入一個URL,我將URI從被調用的URL中抓取出來,並檢查表中是否存儲了URI。如果URI存儲在表中,我將從關係數據庫中的其他表中提取相應的數據。

從拉動其它表中的信息的PHP文件中的一個示例代碼是這樣

<?php 
set_time_limit(2); 
define('MODX_CORE_PATH', '/path/to/modx/core/'); 
define('MODX_CONFIG_KEY','config'); 
require_once MODX_CORE_PATH . 'model/modx/modx.class.php'; 

// Criteria for foreign Database 
$host = 'hostname'; 
$username = 'user'; 
$password = 'password'; 
$dbname = 'database'; 
$port = 3306; 
$charset = 'utf8mb4'; 

$dsn = "mysql:host=$host;dbname=$dbname;port=$port;charset=$charset"; 
$xpdo = new xPDO($dsn, $username, $password); 

// Catch the URI that is called 
$pageURI = $_SERVER["REQUEST_URI"]; 

// Get the language token saved as TV "area" in parent and remove it 
if (!isset($modx)) return ''; 

$top = isset($top) && intval($top) ? $top : 0; 
$id= isset($id) && intval($id) ? intval($id) : $modx->resource->get('id'); 
$topLevel= isset($topLevel) && intval($topLevel) ? intval($topLevel) : 0; 
if ($id && $id != $top) { 
    $pid = $id; 
    $pids = $modx->getParentIds($id); 
    if (!$topLevel || count($pids) >= $topLevel) { 
     while ($parentIds= $modx->getParentIds($id, 1)) { 
      $pid = array_pop($parentIds); 
      if ($pid == $top) { 
       break; 
      } 
      $id = $pid; 
      $parentIds = $modx->getParentIds($id); 
      if ($topLevel && count($parentIds) < $topLevel) { 
       break; 
      } 
     } 
    } 
} 
$parentid = $modx->getObject('modResource', $id); 
$area = "/".$parentid->getTVValue('area'); 
$URL = str_replace($area, '', $pageURI); 
$lang= $parentid->getTVValue('lang'); 

// Issue queries against the foreign database: 
$output = ''; 
$sql = "SELECT epf_application_detail.description FROM epf_application_detail INNER JOIN app_uri ON epf_application_detail.application_id=app_uri.application_id WHERE app_uri.uri = '$URL' AND epf_application_detail.language_code = '$lang'"; 
foreach ($xpdo->query($sql) as $row) { 
    $output .= nl2br($row['description']); 
} 
return $output; 
+4

你在用什麼語言? – koerbcm

+2

你應該有不同類型的緩存(在頁面上,sql查詢和語言)。你有這樣的事嗎? – Adrian

+0

你可以問Stack Overflow團隊。他們對DoS攻擊有某種保護。幾分鐘前我發現了。困難的方法:) –

回答

1

不知道你所使用的語言,這裏是一些僞代碼,讓您開始。

而是每次發射大型查詢您的頁面加載,你可以創建一個名爲類似「緩存」一個單獨的表。您可以運行查詢,然後將查詢中的數據存儲在該緩存表中。然後,當你的頁面加載時,你可以查詢緩存表,這將會小得多,並且當你刷新頁面時不會陷入困境。

僞代碼(可在某個區間用一個cronjob或某事做,讓您的緩存新鮮。):

運行您的十大疑問 對於每個查詢,結果添加到cache像這樣:

query_id | query_data 
---------------------------------------------------- 
     1 | {whatever your query data looks like} 

然後,當你的頁面加載,讓每個查詢收集cache

數據要注意,與高速緩存表,您將需要經常更新它是非常重要的。 (無論是作爲經常你得到更多的數據,或者在設定的時間間隔,比如每5分鐘或什麼的。)

+1

添加一個緩存肯定是一個很好的方法,但由於我有超過30.000.000頁甚至「緩存表」可能會造成一個大的過載。因此,我還需要其他任何保護措施,以便重新發送查詢更加困難,所以DDO保護或簡單的接受按鈕方法可以重新加載 – VolkaRacho

0

你應該做一些服務器端緩存和優化。

如果我是你,我會爲你的數據庫安裝Memcached。

我也會考慮一些像Varnish一樣的靜態緩存,這會將每個頁面緩存爲靜態HTML,第二(和第3,第4,...)請求不需要由PHP和MySQL來處理,這會在第二次加載時(在緩存生命週期內)加載速度更快。

最後,您可以通過安裝APC(或其他操作碼緩存)來幫助PHP端更好地處理數據。