Разбиение на PHP с Couchbase становится очень медленным при больших номерах страниц

Я построил веб-приложение на основе PHP с нумерацией страниц. Я сделал версию для Couchbase и Postgres. Мне пришлось отказаться от N1QL, потому что он имел ужасную производительность (возможно, я задам еще один вопрос для этого). Поэтому я перенес проект из N1QL в представления. Я заметил, что хотя при низком номере страницы (например, 1, 10, 50 с 48 записями на страницу) производительность была лучше, чем у postgres (0,07 с против 0,11 с), но с большим номером страницы (например, 4000 -> 1,5 секунды и 16000). -> 5 секунд) производительность очень плохая. Я использую skip + limit для нумерации страниц с собственной библиотекой CB.

Есть идеи?

PHP:

public static function findByPage($recordsPerPage, $page) {
$query = CouchbaseViewQuery::from("dev_".static::COLLECTION_NAME, "get_".static::COLLECTION_NAME."")->reduce(false)->skip($recordsPerPage*($page-1))->limit($recordsPerPage)->custom(array("full_set"=> "true"));
$data = DB::getDB()->query($query, null, true);
//   var_dump($data);
$objects = array();
foreach($data["rows"] as $row) {
$objects[] = static::find($row["key"]);
}
return $objects;
}

Одно из представлений (они почти все одинаковые):

function (doc, meta) {
if(doc.collection == "green_area") {
emit(doc._id, null);
}
}

0

Решение

Это известное ограничение взглядов. Проблема в том, что нет способа узнать, как далеко проходит запись 4000 индекса просмотра. Когда вы запрашиваете записи 4000-4004, движок представления не должен генерировать только 5 записей, он должен генерировать 4000, которые он немедленно отбрасывает, а затем вручает вам следующие 5. Из-за природы представлений и необходимости разбрасывать собрать из нескольких узлов, чтобы получить один результат, это может быть очень дорого, как вы уже заметили. По этой причине не рекомендуется использовать опцию «пропустить»

Вместо этого рекомендуется использовать параметр «диапазон». Способ, которым это работает, состоит в том, чтобы первоначально указать диапазон как открытый (то есть так, чтобы он включал все записи), примером этого может быть от \ u00 до \ u0fff (полный диапазон символов Юникода) и возвращение, например. 10 записей. Затем вы запомните, что такое 10-я запись, и укажите это как начало диапазона для следующей страницы). Например, если ваша десятая запись была «beer», вы должны указать диапазон от «beer» до \ u0fff. Теперь это будет включать пиво в качестве первого результата, есть два способа решить эту проблему. Первый — запросить 11 результатов и проигнорировать первый. Второй способ решить эту проблему — указать диапазон от «beer \ u00» до «u0fff», который начинается с первой возможной записи после «beer».

Это сообщение в блоге Couchbase содержит более подробную информацию: http://blog.couchbase.com/pagination-couchbase

Стоит отметить, что в N1QL обычно возникает та же проблема, заключающаяся в невозможности угадать, где n-я запись будет в индексе и не обязательно будет решением вашей проблемы.

0

Другие решения

Других решений пока нет …