分页时显然更好:将结果存储在$ _SESSION中或单独查询每个页面

Imagine I've got a database with lots of data, from which users can search.
The result of a typical search is generally around 20-100 rows, which are then paginated (20 rows per page).

I've thought of two approaches to handle the navigation for these pages and would like to know if there are any pros and/or cons to these and if there are any better alternatives.

  1. Query once, store results in $_SESSION variable and filter rows according to current page. The reason I came up with this was to make the data retrieval once, without having to connect to the database for every page the user navigates. I don't know if it's better or worse than the other alternative I've come up with.

    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 page by page. The query and the pagination is pretty straightforward.

    //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 procedures from the alternatives

  1. Is just a procedure with a SELECT query

    SELECT 
        COL1,
        COL2,
        COL...
    FROM TABLE1
    WHERE (
        COL1 LIKE '%'+@search+'%' OR 
        COL2 LIKE '%'+@search+'%' OR 
        COL... LIKE '%'+@search+'%'
    )
    
  2. Is a procedure that creates a temp table and then selects rows from variables start to end.

    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
    

You really can't store all of the results in the _SESSION for at least a couple reasons:

  • Users may make multiple searches simultaneously
  • Search results may change between a user's page loads.

The second point depends on how frequently you update your DB, but is something to consider. The first is major, but you may also be able to get around it if you store the session in a clever way (but you don't want _SESSION getting too large either). This is irrespective of performance.

Another consideration about getting all results at once and storing into _SESSION is that the majority of your users may only make one search request per visit. I know you would like to think they will always look at all 100 results, but if a large chunk of those results are not even being used, you're wasting quite a lot just to save a query or two. It's up to you to figure out how your users navigate.


After reading that this is only going to be used by 20-30 people and only 70 rows a day, I'm satisfied to say you're wasting time trying to improve performance at this point. Go for the code that's easier to update later in case of major changes.

Consider this scenario:

  • User searches a term with 100 results stored in database.
  • You query the database once getting all 100 results and you store them in session.
  • User finds what he was looking for in the first 5 results and leaves the search page.

In the end, you "overheated" database to fetch 95 rows for nothing. What if those 100 results are 1000, or 10.000 ?

In my opinion, getting all the results in a single query and store the results in session is a "reliable method" to reduce performance.