Intereting Posts
Как передать инструкции условия в запрос mySql Невозможно вставить в базу данных MySQL с помощью PDO … Нет ошибок как добавить разные изображения в мою RSS-ленту, используя php Как получить текущее время в ms в PHP? Регулярное выражение для удаления комментариев CSS Почему не совпадают метки времени PHP и Javascript? Как изменить цвет ячейки таблицы на основе информации, хранящейся в таблице базы данных php? Как вызвать внешний файл javascript в PHP? Установка прав пользователя | Команда Artisan не запускается в коде, но отлично работает в командной строке PHP-композитор за HTTP-прокси Предотвращение повторной отправки представления при обновлении браузера Страница на использовала небезопасный контент из в хроме jQuery: Как сделать POST на CLICK? Как изменить свой часовой пояс с помощью метода gmdate? PHP Zend Form – Как установить значения на элементах подформы?

Оптимизация запросов для следующего и предыдущего элементов

Я ищу лучший способ получить следующую и предыдущую записи записи без выполнения полного запроса. У меня есть полностью внедренное решение, и я хотел бы знать, есть ли какие-либо более эффективные подходы к этому.

Предположим, мы строим веб-сайт для фиктивного зеленщика. В дополнение к своим страницам HTML каждую неделю он хочет опубликовать на своем сайте список специальных предложений. Он хочет, чтобы эти предложения находились в реальной таблице базы данных, и пользователи должны иметь возможность сортировать предложения тремя способами.

У каждого элемента также должна быть подробная страница с дополнительной текстовой информацией о предложении и кнопками «предыдущий» и «следующий». «Предыдущие» и «Следующие» кнопки должны указывать на соседние записи в зависимости от сортировки, которую пользователь выбрал для списка .

alt text http://img.ruphp.com/php/Sort.gif?

Очевидно, что «следующая» кнопка «Томаты, класс I» должна быть «Яблоки, класс 1» в первом примере, «Груши, класс I» во втором, и ни один в третьем.

    Задача в подробном представлении состоит в том, чтобы определить следующий и предыдущий элементы без выполнения запроса каждый раз , причем порядок сортировки списка является единственной доступной информацией (скажем, мы получаем это через параметр GET ?sort=offeroftheweek_price и игнорировать последствия для безопасности).

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

    Мой текущий подход в моей CMS использует то, что я назвал «сортировочным кешем». Когда список загружен, я сохраняю позиции позиций в записях в таблице с именем sortingcache .

     name (VARCHAR) items (TEXT) offeroftheweek_unsorted Lettuce; Tomatoes; Apples I; Apples II; Pears offeroftheweek_price Tomatoes;Pears;Apples I; Apples II; Lettuce offeroftheweek_class_asc Apples II;Lettuce;Apples;Pears;Tomatoes 

    очевидно, столбец items действительно заполнен числовыми идентификаторами.

    На странице подробностей я теперь обращаюсь к соответствующей записи sortingcache , sortingcache столбец items , взорву его, ищите текущий идентификатор элемента и верните предыдущий и следующий сосед.

     array("current" => "Tomatoes", "next" => "Pears", "previous" => null ); 

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

    Мои вопросы:

    • Считаете ли вы, что это хорошая практика для поиска соседних записей для разных запросов?

    • Знаете ли вы лучшие практики с точки зрения производительности и простоты? Знаете ли вы что-то, что делает это полностью устаревшим?

    • В теории программирования есть ли название этой проблемы?

    • Является ли название «Сортировочный кэш» подходящим и понятным для этой техники?

    • Существуют ли общепринятые шаблоны для решения этой проблемы? Как они называются?

    Примечание. Мой вопрос заключается не в создании списка, а в том, как отображать подробный вид. Это просто примеры. Мой вопрос – основная функциональность определения соседей записи, когда повторный запрос невозможен, и самый быстрый и дешевый способ добраться туда.

    Если что-то неясно, оставьте комментарий, и я уточню.

    Начав щедрость – может быть, есть дополнительная информация об этом.

    Related of "Оптимизация запросов для следующего и предыдущего элементов"

    Вот идея. Вы можете отключить дорогостоящие операции до обновления, когда grocer вставляет / обновляет новые предложения, а не когда конечный пользователь выбирает данные для просмотра. Это может показаться нединамичным способом обработки данных сортировки, но это может увеличить скорость. И, как мы знаем, всегда существует компромисс между производительностью и другими факторами кодирования.

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

    Таким образом, у вас будут следующие столбцы:

    • Тип сортировки (без сортировки, цены, класса и цены)
    • ID предложения
    • Prev ID
    • Следующий идентификатор

    Когда подробная информация для страницы подробностей предложения запрашивается из базы данных, NextID и PrevID будут частью результатов. Таким образом, вам понадобится только один запрос для каждой подробной страницы.

    Каждый раз, когда предложение вставляется, обновляется или удаляется, вам нужно будет запустить процесс, который проверяет целостность / точность таблицы sorttype.

    У меня есть идея, похожая на Джессику. Однако вместо сохранения ссылок на следующий и предыдущий элементы сортировки вы сохраняете порядок сортировки для каждого типа сортировки. Чтобы найти предыдущую или следующую запись, просто введите строку с SortX = currentSort ++ или SortX = currentSort–.

    Пример:

     Type Class Price Sort1 Sort2 Sort3 Lettuce 2 0.89 0 4 0 Tomatoes 1 1.50 1 0 4 Apples 1 1.10 2 2 2 Apples 2 0.95 3 3 1 Pears 1 1.25 4 1 3 

    Это решение даст очень короткое время запроса и займет меньше места на диске, чем идея Джессики. Однако, как я уверен, вы понимаете, стоимость обновления одной строки данных заметно выше, поскольку вам приходится пересчитывать и хранить все порядки сортировки. Но все же, в зависимости от вашей ситуации, если обновления данных редки и особенно, если они всегда происходят навалом, то это решение может быть лучшим.

    т.е.

     once_per_day add/delete/update all records recalculate sort orders 

    Надеюсь, это полезно.

    У меня тоже были кошмары с этим. Ваш нынешний подход, по-видимому, является лучшим решением даже для списков из 10 предметов. Кэширование идентификаторов представления списка в сеансе http, а затем использование этого для отображения (персонализированного для текущего пользователя) предыдущего / следующего. Это хорошо работает, особенно когда существует слишком много способов фильтрации и сортировки исходного списка элементов вместо 3.
    Кроме того, сохраняя список всех идентификаторов, вы получаете возможность отображать текст "you are at X out of Y" повышающий удобство использования.
    Предыдущий / следующий JIRA

    Кстати, это то, что делает JIRA .

    Чтобы прямо ответить на ваши вопросы:

    • Да, это хорошая практика, потому что она масштабируется без какой-либо дополнительной сложности кода, когда ваш фильтр / сортировка и типы элементов сложнее. Я использую его в производственной системе с 250-килограммовыми статьями с «бесконечными» фильтрами / вариантами сортировки. Обрезка кэшируемых идентификаторов до 1000 также возможна, так как пользователь, скорее всего, никогда не нажмет на предыдущую или следующую более 500 раз (он, скорее всего, вернется и уточнит поиск или paginate).
    • Я не знаю, как лучше. Но если виды, где они ограничены, и это был общедоступный сайт (без сеанса http), я бы, скорее всего, денормализовал.
    • Не знаю.
    • Да, сортировка кеша звучит хорошо. В моем проекте я называю это «предыдущий / следующий по результатам поиска» или «навигация по результатам поиска».
    • Не знаю.

    В общем, я денормализую данные из индексов. Они могут храниться в одних и тех же строках, но я почти всегда извлекаю идентификаторы результатов, а затем делаю отдельную поездку для данных. Это делает кеширование данных очень простым. Это не так важно в PHP, где латентность низкая и пропускная способность высокая, но такая стратегия очень полезна, когда у вас есть приложение с низкой пропускной способностью с низкой пропускной способностью, такое как веб-сайт AJAX, где большая часть сайта отображается в JavaScript.

    Я всегда кэширую списки результатов и результаты сами по себе. Если что-либо влияет на результаты запроса списка, кеш результатов списка обновляется. Если что-то влияет на результаты сами, эти конкретные результаты обновляются. Это позволяет мне обновлять один из них без необходимости регенерировать все, что приводит к эффективному кэшированию.

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

    Поскольку у меня есть весь список кеширования, тривиально найти соседние элементы, не пересматривая базу данных. Если повезет, данные для этих элементов также будут кэшироваться. Это особенно удобно при сортировке данных в JavaScript. Если у меня уже есть копия, кэшированная на клиенте, я могу прибегнуть мгновенно.

    Чтобы конкретно ответить на ваши вопросы:

    • Да, это фантастическая идея, чтобы узнать соседей раньше времени или любую информацию, к которой клиент может получить доступ к следующей, особенно если сейчас стоимость низкая, а затраты на пересчет высоки. Тогда это просто компромисс между дополнительными предварительными расчетами и хранением в зависимости от скорости.
    • С точки зрения производительности и простоты избегайте связывания вещей, которые являются логически разными. Индексы и данные отличаются друг от друга, скорее всего, будут изменены в разное время (например, добавление новой базы данных повлияет на индексы, но не на существующие данные), и, следовательно, их следует получить отдельно. Это может быть несколько менее эффективным с однопоточной точки зрения, но каждый раз, когда вы связываете что-то вместе, вы теряете эффективность кеширования и асинхронность (ключом к масштабированию является асинхронность).
    • Термин для получения данных заранее предполагает предварительную выборку. Предварительная выборка может произойти во время доступа или в фоновом режиме, но до того, как на самом деле необходимы предварительно выбранные данные. Аналогично с предварительным расчетом. Это компромисс между стоимостью, стоимостью хранения и стоимостью при необходимости.
    • «Сортировка кеша» – это имя.
    • Я не знаю.

    Кроме того, когда вы кешируете вещи, кешируйте их на самом общем уровне. Некоторые вещи могут быть специфичными для пользователя (например, результаты для поискового запроса), где другие могут быть агностическими пользователями, например, просматривать каталог. Оба могут извлечь выгоду из кеширования. Запрос каталога может быть частым и сэкономить каждый раз, и поисковый запрос может быть дорогостоящим и сэкономить несколько раз.

    Я не уверен, правильно ли я понял, так что если нет, просто скажи мне;)

    Предположим, что givens – это запрос отсортированного списка и текущего смещения в этом списке, т. Е. У нас есть $query и $n .

    Очень очевидным решением для минимизации запросов было бы получить сразу все данные:

     list($prev, $current, $next) = DB::q($query . ' LIMIT ?i, 3', $n - 1)->fetchAll(PDO::FETCH_NUM); 

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

    Но поскольку это решение слишком просто, я предполагаю, что я что-то не понял.

    Есть так много способов сделать это, как для кожи пресловутой кошки. Итак, вот пара моих.

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

    Затем эту вторую таблицу можно запросить на каждом представлении, и сортировка будет такой же простой, как установка соответствующего порядка сортировки.

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

    В противном случае, если вы хотите избежать соединения с db, вы можете сохранить все данные в php-массиве и сохранить его с помощью memcached. это будет очень быстро и при условии, что ваши списки не слишком велики, будет ресурсоэффективным. и их можно легко отсортировать.

    ОКРУГ КОЛУМБИЯ

    Основные допущения:

    • Специальные предложения еженедельно
    • Мы можем ожидать, что сайт изменится нечасто … возможно, ежедневно?
    • Мы можем контролировать обновления базы данных с помощью эфира API или отвечать через триггеры

    Если сайт меняется ежедневно, я предлагаю, чтобы все страницы статически генерировались в одночасье. Один запрос для каждого порядка сортировки выполняет итерацию и делает все связанные страницы. Даже если есть динамические элементы, есть вероятность, что вы можете адресовать их, включив в них элементы статической страницы. Это обеспечит оптимальное обслуживание страниц и отсутствие загрузки базы данных. Фактически, вы могли бы создать отдельные страницы и предыдущие / следующие элементы, которые включены в страницы. Это может быть более сумасшедшим с 200 способами сортировки, но с 3 я большой поклонник этого.

     ?sort=price include(/sorts/$sort/tomatoes_class_1) /*tomatoes_class_1 is probably a numeric id; sanitize your sort key... use numerics?*/ в ?sort=price include(/sorts/$sort/tomatoes_class_1) /*tomatoes_class_1 is probably a numeric id; sanitize your sort key... use numerics?*/ 

    Если по какой-то причине это невозможно, я прибегну к запоминанию. Memcache популярен для такого рода вещей (каламбур!). Когда что-то подталкивается к базе данных, вы можете выпустить триггер для обновления кеша с правильными значениями. Сделайте это таким же образом, как если бы ваш обновленный элемент существовал в 3 связанных списках – переименуйте соответственно (this.next.prev = this.prev и т. Д.). Из-за этого, пока кеш не переполняется, вы будете извлекать простые значения из памяти в первичном ключе.

    Этот метод потребует некоторого дополнительного кодирования для методов выбора и обновления / вставки, но он должен быть довольно минимальным. В конце концов, вы будете искать [id of tomatoes class 1].price.next . Если этот ключ находится в вашем кеше, то золотой. Если нет, вставьте в кеш и дисплей.

    • Считаете ли вы, что это хорошая практика для поиска соседних записей для разных запросов? Да. Целесообразно выполнять прогноз ожидаемых ожидаемых запросов.
    • Знаете ли вы лучшие практики с точки зрения производительности и простоты? Знаете ли вы что-то, что делает это полностью устаревшим? Надеюсь, что выше
    • В теории программирования есть ли название этой проблемы? Оптимизация?
    • Является ли название «Сортировочный кэш» подходящим и понятным для этой техники? Я не уверен в конкретном подходящем имени. Это кеширование, это кеш-ролик, но я не уверен, что сказать, что у вас есть «сортировочный кеш», это обеспечит мгновенное понимание.
    • Существуют ли общепринятые шаблоны для решения этой проблемы? Как они называются? Кэширование?

    Извините, мои ответы на хвост бесполезны, но я думаю, что мои повествовательные решения должны быть весьма полезными.

    Вы можете сохранить номера строк упорядоченных списков в представлениях , и вы можете достигнуть предыдущего и следующего элементов в списке под (current_rownum-1) и (current_rownum + 1) номерами строк.

    Проблема / datastructur называется двунаправленным графиком или вы можете сказать, что у вас есть несколько связанных списков.

    Если вы считаете это связанным списком, вы можете просто добавить поля в таблицу элементов для каждой сортировки и предыдущего / следующего ключа. Но DB Person убьет вас за это, это похоже на GOTO.

    Если вы думаете о нем как (двунаправленный) график, вы пойдете с ответом Джессики. Основная проблема заключается в том, что обновления заказов – это дорогостоящие операции.

      Item Next Prev AB - BCA CDB ... 

    Если вы измените позицию одного элемента на новый порядок A, C, B, D, вам нужно будет обновить 4 строки.

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

    Мой подход состоял бы в том, чтобы сериализовать () массив после его первого поиска, а затем кэшировать его в отдельную область хранения; будь то memcached / APC / hard-drive / mongoDb / и т. д. и сохраняйте свои данные о местоположении кэша для каждого пользователя отдельно через свои данные сеанса. Фактический объем хранилища, естественно, будет зависеть от размера массива, о котором вы подробно не рассказываете, но memcached масштабируется на нескольких серверах и mongo еще больше при немного большей задержке.

    Вы также не указываете, сколько перестановок есть в реальном мире; например, вам нужно кэшировать отдельные списки для каждого пользователя или вы можете глобально кэшировать на сортировку сортировки, а затем отфильтровывать то, что вам не нужно с помощью PHP ?. В примере, который вы даете, я просто кэширую обе перестановки и сохраняю, какой из двух я нуждался в unserialize () в данных сеанса.

    Когда пользователь вернется на сайт, проверьте значение Time To Live кэшированных данных и повторите его использование, если они все еще действительны. У меня также есть триггер, запущенный на INSERT / UPDATE / DELETE для специальных предложений, которые просто устанавливают поле метки времени в отдельной таблице. Это немедленно укажет, был ли кеш устаревшим, а запрос нужно повторно запустить для очень низкой стоимости запроса. Самое замечательное в использовании триггера для установки одного поля – это не нужно беспокоиться об обрезке старых / избыточных значений из этой таблицы.

    Является ли это подходящим, будет зависеть от размера возвращаемых данных, как часто он был изменен и какие технологии кеширования доступны на вашем сервере.

    Таким образом, у вас есть две задачи:

    1. построить отсортированный список элементов (SELECT с разными ORDER BY)
    2. показать сведения о каждом элементе (ВЫБЕРИТЕ детали из базы данных с возможным кэшированием).

    В чем проблема?

    PS: если упорядоченный список может быть слишком большим, вам просто нужна функциональность PAGER. Могут быть разные реализации, например, вы можете добавить «LIMIT 5» в запрос и предоставить кнопку «Показать следующие 5». Когда эта кнопка нажата, добавляется условие типа «WHERE price <0.89 LIMIT 5».