首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 實現文章上一篇下一篇導航的多種優化方案

     編輯:PHP 綜合知識

核心邏輯:基於 ID 的鄰近查詢

文章上一篇/下一篇功能的本質是:在同一分類下,找到當前文章 ID 之前/之後最近的記錄。關鍵在於 SQL 查詢的寫法直接決定性能。

方案一:子查詢法(標準寫法)

-- 上一篇:ID 最大且小於當前 ID
SELECT article_id, title 
FROM article 
WHERE article_id = (
    SELECT MAX(article_id) 
    FROM article 
    WHERE article_id < $current_id AND cat_id = $cat_id
);

-- 下一篇:ID 最小且大於當前 ID
SELECT article_id, title 
FROM article 
WHERE article_id = (
    SELECT MIN(article_id) 
    FROM article 
    WHERE article_id > $current_id AND cat_id = $cat_id
);

優點:邏輯清晰,利用索引效率高。缺點:需執行兩次查詢。

方案二:ORDER BY + LIMIT(常見但有隱患)

-- 上一篇
SELECT article_id, title 
FROM article 
WHERE article_id < $current_id AND cat_id = $cat_id
ORDER BY article_id DESC 
LIMIT 1;

-- 下一篇
SELECT article_id, title 
FROM article 
WHERE article_id > $current_id AND cat_id = $cat_id
ORDER BY article_id ASC 
LIMIT 1;

注意:若未建立 (cat_id, article_id) 聯合索引,大數據量下 ORDER BY 會觸發 filesort,性能急劇下降。

方案三:UNION ALL 單查詢優化(推薦)

(
    SELECT article_id, title, 'prev' AS type
    FROM article 
    WHERE article_id < $current_id AND cat_id = $cat_id
    ORDER BY article_id DESC LIMIT 1
)
UNION ALL
(
    SELECT article_id, title, 'current' AS type
    FROM article 
    WHERE article_id = $current_id
)
UNION ALL
(
    SELECT article_id, title, 'next' AS type
    FROM article 
    WHERE article_id > $current_id AND cat_id = $cat_id
    ORDER BY article_id ASC LIMIT 1
);

優勢:單次查詢獲取三條記錄,減少數據庫往返。結果集按 type 字段區分,應用層解析即可。

主流 CMS 實現參考

PHPCMS 風格

$id = isset($_GET['id']) ? intval($_GET['id']) : 0;

// 下一篇
$query = mysql_query("SELECT id,title FROM article WHERE id > '$id' ORDER BY id ASC LIMIT 1");
$next = mysql_fetch_array($query);

// 上一篇
$query = mysql_query("SELECT id,title FROM article WHERE id < '$id' ORDER BY id DESC LIMIT 1");
$prev = mysql_fetch_array($query);

PHP 完整封裝類

class ArticleNavigator {
    private $pdo;
    private $table = 'article';
    
    public function __construct(PDO $pdo) {
        $this->pdo = $pdo;
    }
    
    public function getAdjacent($id, $cat_id) {
        $sql = "
            (SELECT id, title, 'prev' AS rel FROM {$this->table} WHERE id < ? AND cat_id = ? ORDER BY id DESC LIMIT 1)
            UNION ALL
            (SELECT id, title, 'current' AS rel FROM {$this->table} WHERE id = ?)
            UNION ALL
            (SELECT id, title, 'next' AS rel FROM {$this->table} WHERE id > ? AND cat_id = ? ORDER BY id ASC LIMIT 1)
        ";
        
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute([$id, $cat_id, $id, $id, $cat_id]);
        $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
        
        $result = ['prev' => null, 'current' => null, 'next' => null];
        foreach ($rows as $row) {
            $result[$row['rel']] = ['id' => $row['id'], 'title' => $row['title']];
        }
        return $result;
    }
}

// 使用
$nav = new ArticleNavigator($pdo);
$adjacent = $nav->getAdjacent(100, 5);
echo "上一篇: {$adjacent['prev']['title']}";
echo "下一篇: {$adjacent['next']['title']}";

索引優化建議

必須建立聯合索引:

ALTER TABLE `article` ADD INDEX `idx_cat_id` (`cat_id`, `article_id`);

此索引可同時支援 WHERE 篩選和 ORDER BY 排序,避免臨時表和文件排序。

邊界情況處理

  • 首篇文章:上一篇返回 null,可隱藏或顯示「已是第一篇」
  • 最新文章:下一篇返回 null,同理處理
  • 分類為空:直接返回空導航
  • 文章被刪除:ID 不連續不影響邏輯,因基於大小比較而非連續性

選擇 UNION ALL 方案配合正確索引,可在千萬級數據量下保持毫秒級響應,是高性能文章導航的最佳實踐。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved