Постраничная навигация на php

Отключение sync_binlog

Параметр sync_binlog определяет логику синхронизации данных из бинлога с диском. Если значение равно 1, запись на диск будет происходить после каждой транзакции. Это делает хранилище очень надежным, но крайне сильно нагружает дисковую подсистему на мастере.


Значение отключит синхронизацию из Mysql, и база данных будет полагаться на ОС в вопросе записи лога на диск. Такое значение может увеличить производительность мастера в несколько раз.

Проверить текущее значение можно так:

mysql -e "show variables like 'sync_binlog'"
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| sync_binlog   | 1     |
+---------------+-------+

Отключить синхронизацию можно без перезагрузки сервера, для этого достаточно выполнить:

Однако не забудьте исправить этот параметр и в my.cnf, чтобы он сохранился после перезагрузки:

В .io мы всегда отключаем синхронизацию бинлога. Это увеличило пропускную способность наших Mysql узлов в 2…3 раза, разгрузив дисковые подсистемы мастеров.

Чтение записей

Другая частая операция при работе с базами данных в PHP — это получение записей из таблиц (запросы типа SELECT). Составим SQL-запрос, который будет использовать выражение. Затем выполним этот запрос с помощью функции , чтобы получить данные из таблицы.

В этом примере показано, как вывести все существующие города из таблицы cities:

В примере выше результат выполнения функции сохранён в переменной . Важно понимать, что в этой переменной находятся не данные из таблицы, а специальный тип данных — так называемая ссылка на результаты запроса. Чтобы получить действительные данные, то есть записи из таблицы, следует использовать другую функцию — — и передать ей единственным параметром эту самую ссылку. Теперь каждый вызов функции будет возвращать следующую запись из всего результирующего набора записей в виде ассоциативного массива

Чтобы получить действительные данные, то есть записи из таблицы, следует использовать другую функцию — — и передать ей единственным параметром эту самую ссылку. Теперь каждый вызов функции будет возвращать следующую запись из всего результирующего набора записей в виде ассоциативного массива.

Цикл здесь используется для «прохода» по всем записям из полученного набора записей. Значение поля каждой записи можно узнать просто обратившись по ключу этого ассоциативного массива.

Как получить сразу все записи в виде двумерного массива

Иногда бывает удобно после запроса на чтение не вызывать в цикле для извлечения очередной записи по порядку, а получить их сразу все одним вызовом. PHP так тоже умеет. Функция вернёт двумерный массив со всеми записями из результата последнего запроса. Перепишем пример с показом существующих городов с её использованием:

Как узнать количество записей

Часто бывает необходимо узнать, сколько всего записей вернёт выполненный SQL запрос. Это может помочь при организации постраничной навигации, или просто в качестве информации. Узнать число записей поможет функция , которой следует передать ссылку на результат запроса.

Использование партиций

Индексы помогут при удалении сравнительно небольших объемов. Однако, если приходится постоянно удалять много (как в нашем случае), стоит посмотреть на партиционирование.

Это значит, что у нас будет возможность манипулировать отдельными партициями. И вместо удаления большого количества записей, мы сможем обьединить их в один блок (партицию) и удалить его одной операцией.

Чтобы проверить это на практике, создадим простую таблицу такой структуры:

tmp: id | title | datetime

Наполним ее тестовыми данными (несколько десятков тысяч записей) и удалим данные:

Запрос выполнился довольно медленно, удалив около 25 тыс. записей:

Query OK, 25750 rows affected (0.27 sec)

Убедимся, что проблема не в индексе (мы его создали, но на всякий случай проверим):

Увидим, что индекс используется — тут все хорошо:

+----+-------------+-------+------------+-------+---------------+----------+---------+------+-------+----------+--------------------------+
| id | select_type | table | partitions | type  | possible_keys | key      | key_len | ref  | rows  | filtered | Extra                    |
+----+-------------+-------+------------+-------+---------------+----------+---------+------+-------+----------+--------------------------+
|  1 | SIMPLE      | tmp   | NULL       | range | datetime      | datetime | 5       | NULL | 28395 |   100.00 | Using where; Using index |
+----+-------------+-------+------------+-------+---------------+----------+---------+------+-------+----------+--------------------------+

Проверим также системную переменную, которая показывает количество удаленных записей из всех InnoDB таблиц:

Variable_name: Innodb_rows_deleted
        Value: 25750

Мы проводим эксперимент в изолированной среде, поэтому других удалений тут не происходит.

Выбор схемы партиционирования

Поскольку мы решаем проблему удаления, нам необходимо иметь схему, в которой мы сможем удобно удалять (чистить) целые партиции. Нам необходимо удалять данные за час, поэтому мы создадим HASH партицию на основе часа из поля datetime:

Проверим, как выглядит распределение наших данных по партициям:

+----------------------------+------------+------------------+
| PARTITION_ORDINAL_POSITION | TABLE_ROWS | PARTITION_METHOD |
+----------------------------+------------+------------------+
|                          1 |          0 | HASH             |
|                          2 |          0 | HASH             |
|                          3 |          0 | HASH             |
|                          4 |          0 | HASH             |
|                          5 |          0 | HASH             |
|                          6 |          0 | HASH             |
|                          7 |          0 | HASH             |
|                          8 |          0 | HASH             |
|                          9 |          0 | HASH             |
|                         10 |          0 | HASH             |
|                         11 |      25394 | HASH             |
|                         12 |      31171 | HASH             |
|                         13 |          0 | HASH             |
|                         14 |          0 | HASH             |
|                         15 |          0 | HASH             |
|                         16 |          0 | HASH             |
|                         17 |          0 | HASH             |
|                         18 |          0 | HASH             |
|                         19 |          0 | HASH             |
|                         20 |          0 | HASH             |
|                         21 |          0 | HASH             |
|                         22 |          0 | HASH             |
|                         23 |          0 | HASH             |
|                         24 |          0 | HASH             |
+----------------------------+------------+------------------+

Как видим, данные в таблице помещены только в две партиции. Они соответствуют текущему и предыдущему часу. Что нам нужно — это очищать партицию за тот час, который нам уже не нужен. Для этого существует операция TRUNCATE :

Если мы проверим счетчик удаленных InnoDB записей, увидим там:

Variable_name: Innodb_rows_deleted
        Value: 25750

Это подтверждает тот факт, что TRUNCATE работает принципиально не так как DELETE. Вместо удаления каждой записи, таблица (или ее партиция) очищается на уровне структуры. Если очень грубо, то Mysql удаляет старый файл данных и создает новый. А эта операция выполняется значительно быстрее построчного удаления.

Когда создавать индексы?

  • Индексы следует создавать по мере обнаружения медленных запросов. В этом поможет slow log в MySQL. Запросы, которые выполняются более 1 секунды являются первыми кандидатами на оптимизацию.
  • Начинайте создание индексов с самых частых запросов. Запрос, выполняющийся секунду, но 1000 раз в день наносит больше ущерба, чем 10-секундный запрос, который выполняется несколько раз в день.
  • Не создавайте индексы на таблицах, число записей в которых меньше нескольких тысяч. Для таких размеров выигрыш от использования индекса будет почти незаметен.
  • Не создавайте индексы заранее, например, в среде разработки. Индексы должны устанавливаться исключительно под форму и тип нагрузки работающей системы.
  • Удаляйте неиспользуемые индексы.

Использование EXPLAIN для анализа индексов

Инструкция EXPLAIN покажет данные об использовании индексов для конкретного запроса. Например:

mysql> EXPLAIN SELECT * FROM users WHERE email = 'golotyuk@gmail.com';
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | users | ALL  | NULL          | NULL | NULL    | NULL |  336 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+

Колонка key показывает используемый индекс. Колонка possible_keys показывает все индексы, которые могут быть использованы для этого запроса. Колонка rows показывает число записей, которые пришлось прочитать базе данных для выполнения этого запроса (в таблице всего 336 записей).

Как видим, в примере не используется ни один индекс. После создания индекса:

mysql> EXPLAIN SELECT * FROM users WHERE email = 'golotyuk@gmail.com';
+----+-------------+-------+-------+---------------+-------+---------+-------+------+-------+
| id | select_type | table | type  | possible_keys | key   | key_len | ref   | rows | Extra |
+----+-------------+-------+-------+---------------+-------+---------+-------+------+-------+
|  1 | SIMPLE      | users | const | email         | email | 386     | const |    1 |       |
+----+-------------+-------+-------+---------------+-------+---------+-------+------+-------+

Прочитана всего одна запись, т.к. был использован индекс.

Проверка длинны составных индексов

Explain также поможет определить правильность использования составного индекса. Проверим запрос из примера (с индексом на колонки age и gender):

mysql> EXPLAIN SELECT * FROM users WHERE age = 29 AND gender = 'male';
+----+-------------+--------+------+---------------+------------+---------+-------------+------+-------------+
| id | select_type | table  | type | possible_keys | key        | key_len | ref         | rows | Extra       |
+----+-------------+--------+------+---------------+------------+---------+-------------+------+-------------+
|  1 | SIMPLE      | users  | ref  | age_gender    | age_gender | 24      | const,const |    1 | Using where |
+----+-------------+--------+------+---------------+------------+---------+-------------+------+-------------+

Значение key_len показывает используемую длину индекса. В нашем случае 24 байта — длинна всего индекса (5 байт age + 19 байт gender).

Если мы выполним изменим точное сравнение на поиск по диапазону, увидим что MySQL использует только часть индекса:

mysql> EXPLAIN SELECT * FROM users WHERE age <= 29 AND gender = 'male';
+----+-------------+--------+------+---------------+------------+---------+------+------+-------------+
| id | select_type | table  | type | possible_keys | key        | key_len | ref  | rows | Extra       |
+----+-------------+--------+------+---------------+------------+---------+------+------+-------------+
|  1 | SIMPLE      | users  | ref  | age_gender    | age_gender | 5       |      |   82 | Using where |
+----+-------------+--------+------+---------------+------------+---------+------+------+-------------+

Это сигнал о том, что созданный индекс не подходит для этого запроса. Если же мы создадим правильный индекс:

mysql> Create index gender_age on users(gender, age);
mysql> EXPLAIN SELECT * FROM users WHERE age < 29 and gender = 'male';
+----+-------------+--------+-------+-----------------------+------------+---------+------+------+-------------+
| id | select_type | table  | type  | possible_keys         | key        | key_len | ref  | rows | Extra       |
+----+-------------+--------+-------+-----------------------+------------+---------+------+------+-------------+
|  1 | SIMPLE      | users  | range | age_gender,gender_age | gender_age | 24      | NULL |   47 | Using where |
+----+-------------+--------+-------+-----------------------+------------+---------+------+------+-------------+

В этом случае MySQL использует весь индекс gender_age, т.к. порядок колонок в нем позволяет сделать эту выборку.

Постраничная навигация в компонентах

Добавить параметры постраничной навигации на страницу настройки компонента:

<?php
/*
 * Файл local/components/tokmakov/iblock.section/.parameters.php
 */
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED!==true) die();

/*
 * Настройки компонента
 */
$arComponentParameters = array(
    /*...*/
);

// настройка постраничной навигации
CIBlockParametersAddPagerSettings(
    $arComponentParameters,
    'Элементы',  // $pager_title
    false,       // $bDescNumbering
    true,        // $bShowAllParam
);

// добавляем еще одну настройку — на случай, если раздел инфоблока не найден
CIBlockParametersAdd404Settings($arComponentParameters, $arCurrentValues);

Постраничная навигация в коде компонента:

<?php
/*
 * Файл local/components/infoblock/iblock.section/component.php
 */
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED!==true) die();

if (!CModuleIncludeModule('iblock')) {
    ShowError('Модуль «Информационные блоки» не установлен');
    return;
}

// запрещаем сохранение в сессии номера последней страницы 
// при стандартной постраничной навигации
CPageOptionSetOptionString('main', 'nav_page_in_session', 'N');

if (!isset($arParams'CACHE_TIME')) {
    $arParams'CACHE_TIME' = 3600;
}

// тип инфоблока
$arParams'IBLOCK_TYPE' = trim($arParams'IBLOCK_TYPE');
// идентификатор инфоблока
$arParams'IBLOCK_ID' = intval($arParams'IBLOCK_ID');

// количество элементов на страницу
$arParams'ELEMENT_COUNT' = intval($arParams'ELEMENT_COUNT');
if ($arParams'ELEMENT_COUNT' <= ) {
    $arParams'ELEMENT_COUNT' = 3;
}

// учитывать права доступа при кешировании?
$arParams'CACHE_GROUPS' = $arParams'CACHE_GROUPS'=='Y';

// показывать постраничную навигацию вверху списка элементов?
$arParams'DISPLAY_TOP_PAGER' = $arParams'DISPLAY_TOP_PAGER'=='Y';
// показывать постраничную навигацию внизу списка элементов?
$arParams'DISPLAY_BOTTOM_PAGER' = $arParams'DISPLAY_BOTTOM_PAGER'=='Y';
// поясняющий текст для постраничной навигации
$arParams'PAGER_TITLE' = trim($arParams'PAGER_TITLE');
// всегда показывать постраничную навигацию, даже если в этом нет необходимости
$arParams'PAGER_SHOW_ALWAYS' = $arParams'PAGER_SHOW_ALWAYS'=='Y';
// имя шаблона постраничной навигации
$arParams'PAGER_TEMPLATE' = trim($arParams'PAGER_TEMPLATE');
// показывать ссылку «Все элементы», с помощью которой можно показать все элементы списка?
$arParams'PAGER_SHOW_ALL' = $arParams'PAGER_SHOW_ALL'=='Y';

// получаем все параметры постраничной навигации, от которых будет зависеть кеш
$arNavParams = null;
$arNavigation = false;
if ($arParams'DISPLAY_TOP_PAGER' || $arParams'DISPLAY_BOTTOM_PAGER') {
    $arNavParams = array(
        'nPageSize' => $arParams'ELEMENT_COUNT', // количество элементов на странице
        'bShowAll' => $arParams'PAGER_SHOW_ALL', // показывать ссылку «Все элементы»?
    );
    $arNavigation = CDBResultGetNavParams($arNavParams);
}

$cacheDependence = array($arParams'CACHE_GROUPS' ? $USER->GetGroups()  false, $arNavigation);
if ($this->StartResultCache(false, $cacheDependence)) {

    /*
     * Получаем информацию о разделе инфоблока
     */

    // какие поля раздела инфоблока выбираем
    $arSelect = array(/*...*/);
    // условия выборки раздела инфоблока
    $arFilter = array(/*...*/);
    // выполняем запрос к базе данных
    $rsSection = CIBlockSectionGetList(array(), $arFilter, false, $arSelect);
    $arResult = $rsSection->GetNext();

    if ($arResult) {
        /*
         * Получаем элементы этого раздела инфоблока
         */

        // какие поля элементов выбираем
        $arSelect = array(/*...*/);
        // условия выборки элементов инфоблока
        $arFilter = array(/*...*/);
        // сортировка элементов
        $arSort = array(/*...*/);
        // выполняем запрос к базе данных
        $rsElements = CIBlockElementGetList($arSort, $arFilter, false, $arNavParams, $arSelect);

        $arResult'ITEMS' = array();
        while ($arItem = $rsElements->GetNext()) {
            $arResult'ITEMS' = $arItem;
        }

        /*
         * Постраничная навигация
         */
        $arResult'NAV_STRING' = $rsElements->GetPageNavString(
            $arParams'PAGER_TITLE',
            $arParams'PAGER_TEMPLATE',
            $arParams'PAGER_SHOW_ALWAYS',
            $this
        );

        $this->SetResultCacheKeys(
            /*...*/
        );
        $this->IncludeComponentTemplate();
    } else { // если раздел инфоблока не найден
        $this->AbortResultCache();
        \Bitrix\Iblock\Component\Toolsprocess404(/*...*/);
    }
}

// кэш не затронет все действия ниже, здесь работаем уже с другим $arResult
if (isset($arResult'ID')) {
    /*...*/
}

◆ initFromUri()

initFromUri ( )

Initializes the navigation from URI.

См. определение в файле main/lib/ui/pagenavigation.php строка

48  {

49  $navParams = array();

50 

51  = ()->getRequest();

52 

53  if(($value = ->getQuery($this->id)) !== null)


54  {

55 

56  $params = explode(«-«, $value);

57  for($i = 0, $n = count($params); $i < $n; $i += 2)

58  {

59  $navParams] = $params;

60  }

61  }

62  else

63  {

64 

65  $matches = array();

66  if(preg_match(«‘/».preg_quote($this->id, «‘»).»/page-(+|all)+(/size-(+))?'», ->getRequestUri(), $matches))

67  {

68  $navParams = $matches;

69  if(isset($matches))

70  {

71  $navParams = $matches;

72  }

73  }

74  }

75 

76  if(isset($navParams))

77  {

78 

79  if(in_array($navParams, $this->pageSizes))

80  {

81  $this->((int)$navParams);

82  }

83  }


84 

85  if(isset($navParams))

86  {

87  if($navParams == «all» && $this->allowAll == true)

88  {

89 

90  $this->allRecords = true;

91  }

92  else

93  {

94 

95  = (int)$navParams;

96  if( >= 1)

97  {

98  if($this->recordCount !== null)

99  {

100  $maxPage = $this->();

101  if( > $maxPage)

102  {

103  = $maxPage;

104  }

105  }

106  $this->();

107  }

108  }

109  }

110  }

Шаблон списка новостей

Файл шаблона . Этот шаблон используется как для показа всех статей блога, так и для показа статей выбранного раздела инфоблока. Странно, но в шаблоне не предусмотрен вывод заголовков и вывод подразделов текущего раздела инфоблока. Давайте это исправим и создадим файл :

<?php
/**
 * Файл local/templates/blog/components/bitrix/news/blog/bitrix/news.list/.default/result_modifier.php
 */
if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die();

/*
 * Получаем информацию о текущем разделе инфоблока. Здесь возможны две ситуации:
 * - первая — мы имеем дело с обычным разделом инфоблока, который выводит список
 *   элементов этого раздела и всех его потомков
 * - вторая — мы имеем дело с корневым разделом инфоблока, который выводит список
 *   всех элементов, которые есть в инфоблоке
 * Для обоих случаев используется простой компонент bitrix:news.list и нам надо
 * как-то различать эти две ситуации. Но в любом случае у страницы должен быть
 * заголовок и список подразделов текущего раздела — для навигации. Потому как в
 * стандартном компоненте Битрикс этого не предусмотрено. Или я чего-то не понял.
 */

$arParams'PARENT_SECTION' = intval($arParams'PARENT_SECTION');

if ($arParams'PARENT_SECTION' > ) { // это обычный раздел инфоблока
    /*
     * Сначала получаем инфомацию о текущем разделе
     */
    $arResult'SECTION_DATA''ROOT' = false;
    // какие поля раздела инфоблока выбираем
    $arSelect = array(
        'NAME',
        'DESCRIPTION',
    );
    // условия выборки
    $arFilter = array(
        'IBLOCK_ID' => $arResult'ID',      // идентификатор инфоблока
        'IBLOCK_ACTIVE' => 'Y',              // инфоблок должен быть активен
        'ID' => $arParams'PARENT_SECTION', // идентификатор раздела
        'ACTIVE' => 'Y',                     // раздел должен быть активным
    );
    // сортировка
    $arSort = array(
        'SORT' => 'ASC'
    );
    // выполняем запрос к базе данных
    $dbResult = CIBlockSectionGetList(
        $arSort,
        $arFilter,
        false,
        $arSelect
    );
    if ($arSection = $dbResult->GetNext()) {
        $arResult'SECTION_DATA' = $arSection;
    }
    /*
     * А потом информацию о подразделах текущего раздела
     */
    // какие поля подразделов выбираем
    $arSelect = array(
        'ID',
        'NAME',
        'DESCRIPTION',
        'SECTION_PAGE_URL'
    );
    // условия выборки подразделов
    $arFilter = array(
        'IBLOCK_ID' => $arResult'ID', // идентификатор инфоблока
        'IBLOCK_ACTIVE' => 'Y',         // инфоблок должен быть активен
        'ACTIVE' => 'Y',                // только активные разделы
        'SECTION_ID' => $arParams'PARENT_SECTION'
    );
    // сортировка разделов
    $arSort = array(
        'SORT' => 'ASC'
    );
    // выполняем запрос к базе данных
    $dbResult = CIBlockSectionGetList(
        $arSort,
        $arFilter,
        false,
        $arSelect
    );
    // шаблон ссылки на страницу с содержимым подраздела
    $dbResult->SetUrlTemplates('', $arParams'SECTION_URL');
    while ($arSection = $dbResult->GetNext()) {
        $arResult'SECTION_DATA''CHILDS' = $arSection;
    }
} else { // это корень, делаем виртуальный раздел
    /*
     * Сначала получаем инфомацию о корневом разделе
     */
    $arResult'SECTION_DATA''ROOT' = true;
    // в качестве имени корневого раздела используем имя инфоблока
    $arResult'SECTION_DATA''NAME' = $arResult'NAME';
    // в качестве описания корневого раздела используем описание инфоблока
    $arResult'SECTION_DATA''DESCRIPTION' = $arResult'DESCRIPTION';
    /*
     * А потом информацию о подразделах корневого раздела
     */
    // какие поля подразделов выбираем
    $arSelect = array(
        'ID',
        'NAME',
        'DESCRIPTION',
        'SECTION_PAGE_URL'
    );
    // условия выборки подразделов
    $arFilter = array(
        'IBLOCK_ID' => $arResult'ID', // идентификатор инфоблока
        'IBLOCK_ACTIVE' => 'Y',         // инфоблок должен быть активен
        'ACTIVE' => 'Y',                // только активные разделы
        'SECTION_ID' => false           // выбираем разделы верхнего уровня
    );
    // сортировка разделов
    $arSort = array(
        'SORT' => 'ASC'
    );
    // выполняем запрос к базе данных
    $dbResult = CIBlockSectionGetList(
        $arSort,
        $arFilter,
        false,
        $arSelect
    );
    // шаблон ссылки на страницу с содержимым подраздела
    $dbResult->SetUrlTemplates('', $arParams'SECTION_URL');
    while ($arSection = $dbResult->GetNext()) {
        $arResult'SECTION_DATA''CHILDS' = $arSection;
    }
}

Теперь можно заняться шаблоном списка статей блога:

Селективность индексов

Вернемся к запросу:

Для такого запроса необходимо создать составной индекс. Но как правильно выбрать последовательность колонок в индексе? Варианта два:

  • age, gender
  • gender, age

Подойдут оба. Но работать они будут с разной эффективностью.


Чтобы понять это, рассмотрим уникальность значений каждой колонки и количество соответствующих записей в таблице:

mysql> select age, count(*) from users group by age;
+------+----------+
| age  | count(*) |
+------+----------+
|   15 |      160 |
|   16 |      250 |
|        ...      |
|   76 |      210 |
|   85 |      230 |
+------+----------+
68 rows in set (0.00 sec)

mysql> select gender, count(*) from users group by gender;
+--------+----------+
| gender | count(*) |
+--------+----------+
| female |     8740 |
| male   |     4500 |
+--------+----------+
2 rows in set (0.00 sec)

Эта информация говорит нам вот о чем:

  1. Любое значение колонки age обычно содержит около 200 записей.
  2. Любое значение колонки gender — около 6000 записей.

Если колонка age будет идти первой в индексе, тогда MySQL после первой части индекса сократит количество записей до 200. Останется сделать выборку по ним. Если же колонка gender будет идти первой, то количество записей будет сокращено до 6000 после первой части индекса. Т.е. на порядок больше, чем в случае age.

Это значит, что индекс age_gender будет работать лучше, чем gender_age.

Селективность колонки определяется количеством записей в таблице с одинаковыми значениями. Когда записей с одинаковым значением мало — селективность высокая. Такие колонки необходимо использовать первыми в составных индексах.

Поиск данных в MySQL

Таблицы MySQL — это обычные файлы. Выполним запрос такого вида:

MySQL при этом открывает файл, где хранятся данные из таблицы users. А дальше — начинает перебирать весь файл, чтобы найти нужные записи.

Кроме этого, MySQL будет сравнивать данные в каждой строке таблицы со значением в запросе. Допустим работа ведется с таблицей, в которой есть 10 записей. Тогда MySQL прочитает все 10 записей, сравнит колонку age каждой из них со значением 29 и отберет только подходящие данные:

Итак, есть две проблемы при чтении данных:

  • Низкая скорость чтения файлов из-за расположения блоков в разных частях диска (фрагментация).
  • Большое количество операций сравнения для поиска нужных данных.

Основные настройки WP-PageNavi

Теперь давайте немного настроим вывод навигации страниц и разделов площадки. Для этого заходим в админ панель wordpress. Находим вкладку «Параметры» далее «Список страниц».

Перед нами откроется окно с настройками плагина.

В поле «Шаблон общего списка страниц» я добавил слово «Страница» в итоге у меня выводится небольшое пояснение к текущей и общему количеству страниц.

В поля «Первая и последняя страница» вы можете задать название для заданных кнопок.

В полях «Предыдущая и следующая страница» можно поменять такой элемент, как стрелочки для перехода на другую страницу.

Чуть ниже вы можете отредактировать стиль списка страниц (обычный или выпадающий). Указать диапазон и количество страниц, а так же задать коэффициент для диапазонов страниц.

Для самых продвинутых можно пойти еще дальше и попробовать изменить внешний вид плагина wp-pagenavi. Для этого необходимо отредактировать файл pagenavi-css.css, который отвечает за вывод стилевого оформления.

Его адрес у меня такой:

httpdocswp-contentpluginswp-pagenavipagenavi-css.css

Экспериментируйте, и у вас обязательно все получится, только не забывайте делать резервные копии редактируемых файлов.

Если есть еще какие-то сомнения, обязательно посмотрите видео по установке и настройке данного модуля.

https://youtube.com/watch?v=gcy1SZTV5iE

Отображение результатов страничного вывода

При вызове методов и на конструкторе запросов или запросе Eloquent вы получите экземпляр страничного вывода. Для метода это будет экземпляр Illuminate\Pagination\LengthAwarePaginator. А для метода это будет экземпляр Illuminate\Pagination\Paginator. Эти объекты предоставляют несколько методов для вывода конечного набора. В дополнение к этим вспомогательным методам экземпляры страничного вывода — итераторы, к ним можно обращаться как к массивам. Итак, когда вы получили результаты, вы можете вывести их и создать ссылки на страницы с помощью Blade:

+ 5.0

добавлено в

5.0

(08.02.2016)

Итак, когда вы получили результаты, вы можете вывести их и создать ссылки на страницы методом :

Метод (для версии 5.1 и ранее ) выведет ссылки на остальные страницы в конечном наборе. Каждая из этих ссылок уже будет содержать правильную переменную строки запроса page. Помните, сгенерированный методом HTML-код совместим с CSS-фреймворком Bootstrap.

+ 5.1 5.0

добавлено в

5.1

(19.06.2016) 5.0

(08.02.2016)

При вызове метода из Blade-шаблона не забудьте использовать синтаксис для экранирования HTML-ссылок.

Настройка URI для вывода ссылок

Настроить URI для вывода ссылок на страницы можно с помощью метода . Например, если вы хотите получить ссылки вида http://example.com/custom/url?page=N, вам надо передать custom/url в метод :

Параметры в ссылках

Вы можете добавить параметры запросов к ссылкам страниц с помощью метода . Например, чтобы добавить &sort=votes к каждой страничной ссылке, вам надо вызвать вот так:

Код выше создаст ссылки наподобие:

http://example.com/something?page=2&sort=votes

Если вы хотите добавить «хэш-фрагмент» в URL-адреса страничного вывода, вы можете использовать метод . Например, чтобы добавить #foo к каждой страничной ссылке, вам надо вызвать вот так:

Вызов этого метода сгенерирует URL-адреса наподобие:

http://example.com/something?page=2#foo

Преобразование в JSON

Классы страничного вывода Laravel реализуют контракт интерфейса Illuminate\Contracts\Support\Jsonable и предоставляют метод , поэтому можно очень легко конвертировать ваш страничный вывод в JSON. Вы также можете преобразовать экземпляр страничного вывода в JSON, просто вернув его из маршрута или действия контроллера.

JSON-форма экземпляра будет включать некоторые «мета-данные», такие как total, current_page, last_page и другие. Данные экземпляра будут доступны через ключ data в массиве JSON. Вот пример JSON, созданного при помощи возврата экземпляра страничного вывода из маршрута:

+ 5.3

добавлено в

5.3

(28.01.2017)

Настройка представления страничного вывода

По умолчанию отрисованные представления для отображения ссылок страничного вывода совместимы с CSS-фреймворком Bootstrap. Но если вы не используете Bootstrap, вы можете определить свои собственные представления для отрисовки этих ссылок. При вызове метода на экземпляре страничного вывода передайте первым аргументом имя представления:

Но самый простой способ изменить представления страничного вывода — экспортировать их в ваш каталог resources/views/vendor с помощью команды :

Эта команда поместит представления в папку resources/views/vendor/pagination. Файл default.blade.php в этой папке является стандартным представлением страничного вывода. Просто отредактируйте этот файл, чтобы изменить HTML страничного вывода.

  • (для версии 5.2 и выше)
  • (для версии 5.2 и выше)
  • (недоступен при использовании simplePaginate)
  • (недоступен при использовании simplePaginate)

С этим читают