Сам по себе еще один запрос - это не лишняя работа, а ерунда на постном масле.
Вопрос не в том, сколько запросов выполняется, а что именно они делают.
И в данном случае эти два запроса делают ужас, летящий на крыльях ночи. Я сейчас расскажу, что делает ваш код.
Сначала этот код просит базу данных отправить в РНР
все найденные запросом строки. Все. Без лимита. Чтобы РНР мог посчитать их и потом выбросить.
После этого код
еще раз просит базу отправить, только не все строки, а только часть. И теперь РНР уже не выбрасывает полученные строки, а честно выводит.
Понятное дело, что смысла в этих замысловатых телодвижениях - ноль целых, ноль десятых.
Как правильно получить общее количество найденных строк?
Надо попросить базу посчитать их
Ну и разумеется, использование prepare вместе с доморощенной и небезопасной функцией "clearStr" - это вообще за гранью добра и зла. Это примерно как хранить миллион в сейфе, но не запирать его на ключ, а подпирать дощечкой.
$GLOBALS["mysqlcon"] - это отдельный ужас, но на фоне всего остального меркнет.
Правильный код будет таким
$sql = "SELECT count(*) FROM post WHERE MATCH (tags) AGAINST (? IN BOOLEAN MODE)";
$STH = $GLOBALS["mysqlcon"]->prepare($sql);
$STH->execute([$_GET['search']]);
$totalPages=ceil($STH->fetchColumn()/$numPosts); //Узнаем сколько всего страниц существует
$sql = "SELECT * FROM post WHERE MATCH (tags) AGAINST (? IN BOOLEAN MODE) LIMIT ?,?";
$STH = $GLOBALS["mysqlcon"]->prepare($sql);
$STH->execute([$_GET['search'],$start, $numPosts]);
Поскольку все советуют синглтон, вот готовый пример:
https://phpdelusions.net/pdo/pdo_wrapper#singleton
С ним, кроме прочего, код будет короче
$sql = "SELECT count(*) FROM post WHERE MATCH (tags) AGAINST (? IN BOOLEAN MODE)";
$numRows = DB::run($sql, [$_GET['search']])->fetchColumn();
$totalPages=ceil($numRows/$numPosts); //Узнаем сколько всего страниц существует
$sql = "SELECT * FROM post WHERE MATCH (tags) AGAINST (? IN BOOLEAN MODE) LIMIT ?,?";
$STH = DB::run($sql, [$_GET['search'],$start, $numPosts]);