分页时明显更好的是:以 $_SESSION 存储结果或单独查询每个页面


What is demonstrably better when paginating: storing result in $_SESSION or querying every page separately

>想象一下,我有一个包含大量数据的数据库,用户可以从中搜索。
典型搜索的结果通常约为 20-100 行,然后进行分页(每页 20 行)。

我想到了两种处理这些页面导航的方法,想知道这些是否有任何优点和/或缺点,以及是否有更好的选择。

  1. 查询一次,将结果存储在变量$_SESSION并根据当前页面筛选行。我想出这个的原因是进行一次数据检索,而不必为用户导航的每个页面连接到数据库。我不知道它比我想出的其他替代方案更好还是更差。

    session_start();
    $search = rawurldecode($_GET['search']);   //search word
    $interval = rawurldecode($_GET['interval']); //rows per page
    $page = rawurldecode($_GET['page']);    //page
    $min_row = $interval * ($page-1)+1;
    $max_row = $interval * $page;
    //query if (no results stored or first page) && the current search is not the previous search                               
    if((empty($_SESSION['SEARCH_RESULTS']) || $page == 1) && $_SESSION['SEARCH_RESULTS']['TERM'] != $search){
        $_SESSION['SEARCH_RESULTS'] = array();
        $_SESSION['SEARCH_RESULTS']['TERM'] = $search;
        $query = "exec usp_Search '$search'";
        $dbh = new DBH;
        $dbh->Connect()->Query($query);
        while($row = $dbh->Fetch_Array()){  
            $_SESSION['SEARCH_RESULTS']['ROWS'][] = $row;                           
        }
    }
    for($j = 0; $j < count($_SESSION['SEARCH_RESULTS']['ROWS']); $j++){
        $row = $_SESSION['SEARCH_RESULTS']['ROWS'][$j];
        //ignore all other rows not on the page
        if($j < ($min_row-1) || $j > $max_row) continue; 
        //print stuff
    }
    
  2. 逐页查询。查询和分页非常简单。

    //Query
    $search = rawurldecode($_GET['search']);
    $interval = rawurldecode($_GET['interval']);
    $page = rawurldecode($_GET['page']);
    $min_row = $interval * ($page-1)+1;
    $max_row = $interval * $page;
    $query = "exec usp_Search '$search', $min_row, $max_row";
    $dbh = new DBH;
    $dbh->Connect()->Query($query);
    while($row = $dbh->Fetch_Array()){ 
        //print stuff                       
    }
    

替代方案中的 SQL 过程

  1. 只是一个带有 SELECT 查询的过程

    SELECT 
        COL1,
        COL2,
        COL...
    FROM TABLE1
    WHERE (
        COL1 LIKE '%'+@search+'%' OR 
        COL2 LIKE '%'+@search+'%' OR 
        COL... LIKE '%'+@search+'%'
    )
    
  2. 是一个创建临时表,然后从变量中从开始到结束选择行的过程。

    SELECT 
        COL1,
        COL2,
        COL...,
        ROW_NUMBER() OVER (ORDER BY COL1) AS [ROW_NUMBER]
    INTO #result
    FROM TABLE1
    WHERE (
        COL1 LIKE '%'+@search+'%' OR 
        COL2 LIKE '%'+@search+'%' OR 
        COL... LIKE '%'+@search+'%'
    )   
    SELECT 
        COL1,
        COL2,
        COL...
    FROM #result
    WHERE ROW_NUMBER BETWEEN @row_start AND @row_end
    

由于至少以下几个原因,您确实无法将所有结果存储在_SESSION中:

  • 用户可以同时进行多次搜索
  • 搜索结果可能会在用户页面加载之间发生变化。

第二点取决于您更新数据库的频率,但需要考虑这一点。 第一个是主要的,但如果你以巧妙的方式存储会话,你也可以绕过它(但你也不想_SESSION变得太大)。 这与性能无关。

一次获取所有结果并存储到_SESSION的另一个注意事项是,大多数用户每次访问可能只发出一个搜索请求。 我知道你认为他们总是会查看所有 100 个结果,但如果这些结果中的很大一部分甚至没有被使用,你只是为了保存一两个查询就浪费了很多。 由您来弄清楚用户如何导航。


在读到这只会被 20-30 人使用并且每天只有 70 行之后,我很满意地说你在浪费时间试图提高性能。 选择以后在发生重大更改时更容易更新的代码。

请考虑以下场景:

  • 用户搜索数据库中存储了 100 个结果的术语。
  • 查询数据库一次,获取所有 100 个结果,并将它们存储在会话中。
  • 用户在前 5 个结果中找到他要查找的内容并离开搜索页面。

最后,您"过热"数据库以免费获取 95 行。如果这 100 个结果是 1000 或 10.000 怎么办?

在我看来,在单个查询中获取所有结果并将结果存储在会话中是降低性能的"可靠方法"。