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.
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
}
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
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+'%'
)
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:
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:
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.