在網站中,經常有一些資料是相同的,並不必要每一次刷新都重建,若果這在一個大的 DB 資料庫,或一個複雜的 SQL 查詢中,很消耗資源。將查詢結果進行緩存是一個極好的解決方法。
Drupal 7 新增了 API drupal_render_cache_by_query() 來嘗試解決以上問題,主要用作緩存相同的 DB Query 的結果,為 DB Server 減輕查詢負擔。也就是說,當 DB Query 有改變,這會重新產生,否則這會直接由 DB 取得預早的緩存結果。
在 Drupal Core 中也只有在 Forum Block 中使用過一次。由於太新了,這唯一的一次實例也出錯了,以下是修正的版本示範:
function forum_block_view($delta = '') {
$query = db_select('forum_index', 'f')
->fields('f')
->addTag('node_access');
switch ($delta) {
case 'active':
$title = t('Active forum topics');
$query
->orderBy('f.last_comment_timestamp', 'DESC')
->range(0, variable_get('forum_block_num_active', '5'));
break;
case 'new':
$title = t('New forum topics');
$query
->orderBy('f.created', 'DESC')
->range(0, variable_get('forum_block_num_new', '5'));
break;
}
$block['subject'] = $title;
// Cache based on the altered query. Enables us to cache with node access enabled.
$block['content'] = drupal_render_cache_by_query($query, 'forum_block_view', CACHE_TEMPORARY, DRUPAL_CACHE_PER_ROLE);
$block['content']['#access'] = user_access('access content');
return $block;
}
上面,我們很清楚可見:
- $query - db_select() Object (沒有執行 $query->execute())
- forum_block_view - 這是一個 callback,將會呼叫 forum_block_view_pre_render 進行後續處理,並將處理好的數據作為緩存資料
- CACHE_TEMPORARY - 緩存的時間性設定,可參考 cache_set() $expire
-
DRUPAL_CACHE_PER_ROLE - 這項是緩存的方式,比如:
DRUPAL_CACHE_PER_ROLE (以角色區分)
DRUPAL_CACHE_PER_PAGE (以每一頁面區分)。
也可以兩者同時區分:"DRUPAL_CACHE_PER_PAGE | DRUPAL_CACHE_PER_ROLE" (既以頁面又以角色區分)。
還有一個是 DRUPAL_CACHE_PER_USER。選擇那一個要按實際需求,過份濫用也有可能會造成 DB 壓力。
多善用 :)

4 個回應主題: Drupal API: drupal_render_cache_by_query [基於 DB Query,緩存你的查詢結果]
Kay 研究得很細喔。
不知道在 Taiwan,有沒有那麼大型的網站,可以用到這個函數。
嗯... 你說的也是,不知多少網站與模組會用到,很多都基本用舊有的 CACHE 就可以。
就以上 FORUM 例子,其實在 D7 中的 FORUM BLOCK 也幾乎不太必要這東西了 (D7 基於 forum_index 查詢,根據我之前測試,即使沒有這東西,過百萬主題也不會造成效能問題)。
不错,drupal7真的改进了不少,可是有时候小型网站用d7,反而感觉更慢了?
我沒有實質測試過,按看過的結果,簡單頁面,是 D6 快一點,但當讀取 10個 NODES 或 數十 COMMENTS 時,D7 有優化 (node_load_multiple),另外,如果 BLOCK 很多,我估計在 D7 是有優勢
此刻為止,Drupal 7 Dev 版本會比 7.0 stable 要快一點 (建議大家用 Dev version,很多修正)
寫下您的回覆