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

голоса
28

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

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

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

альтернативный текст http://www.pekkagaiser.com/stuff/Sort.gif?

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

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

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

Мой текущий подход в моей 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записи, принести itemsстолбец, взорвать его, искать для текущего элемента ID, и возврата к предыдущему и следующему соседу.

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

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

Мои вопросы:

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

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

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

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

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

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

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

Начиная Баунти - может быть, есть еще немного информации об этом там.

Задан 22/02/2010 в 12:06
источник пользователем
На других языках...                            


11 ответов

голоса
-3

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

  1. построить отсортированный список элементов (селекция с различным ORDER BY)
  2. показать подробную информацию о каждом пункте (ВЫБРАТЬ детали из базы данных с возможностью кэширования).

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

PS: если упорядоченный список может быть слишком большим, вам просто нужна функциональность ПЕЙДЖЕРА реализована. Там могут быть различные реализации, например, вы можете добавить «LIMIT 5» в запросе и обеспечить «Показать следующий 5» кнопку. При нажатии этой кнопки, «где цена <0,89 LIMIT 5» добавляется условие, как.

Ответил 22/02/2010 в 15:04
источник пользователем

голоса
16

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

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

Таким образом, вы бы эти столбцы:

  • Сортировка Тип (Несортиры, Цена, класс и цена Описание изделие)
  • предложение ID
  • Предыдущая ID
  • Следующая ID

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

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

Ответил 22/02/2010 в 20:20
источник пользователем

голоса
1

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

Допустим, что данности являются запросом для отсортированного списка и тока смещения в этом списке, то есть у нас есть $queryи $n.

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

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

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

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

Ответил 07/02/2011 в 20:31
источник пользователем

голоса
2

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

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

Для того, чтобы прямо ответить на ваши вопросы:

  • Да, это хорошая практика, потому что весы без дополнительной сложности коды, когда ваш фильтр / сортировка и типов элементов кукарекать сложнее. Я использую его в производственной системе с 250K статей с «бесконечными» вариациями фильтров / сортировки. Обрезка Cacheable идентификаторов 1000 также возможность, так как пользователь не будет, скорее всего, не нажимайте на пред или рядом более чем в 500 раз (Он, скорее всего, вернуться назад и результаты поиска или постраничной).
  • Я не знаю лучшего способа. Но если виды, где ограничены, и это был публичный сайт (без HTTP сессии), то я бы, скорее всего, денормализовать.
  • Не знаю.
  • Да, сортировка кэш звучит хорошо. В моем проекте я называю это «предыдущий / следующий в результатах поиска» или «навигация по результатам поиска».
  • Не знаю.
Ответил 07/02/2011 в 21:04
источник пользователем

голоса
2

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

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

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

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

Для того, чтобы ответить на ваши вопросы конкретно:

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

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

Ответил 09/02/2011 в 08:00
источник пользователем

голоса
0

Есть много способов сделать это, чтобы кожа общеизвестный кошки. Так вот несколько моих.

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

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

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

С другой стороны, если вы хотите, чтобы избежать даже подключения к БД, то вы можете хранить все данные в массиве PHP и сохранить его с помощью Memcached. это было бы очень быстро, и при условии, ваши списки не были слишком огромный ресурс будет эффективным. и может быть легко отсортирован.

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

Ответил 11/02/2011 в 05:19
источник пользователем

голоса
0

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

  • Скидки еженедельно
  • Можно ожидать, что сайт, чтобы изменить нечасто ... наверное каждый день?
  • Мы можем контролировать обновление базы данных с эфиром с 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?*/

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

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

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

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

Ответил 11/02/2011 в 18:13
источник пользователем

голоса
0

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

Ответил 12/02/2011 в 14:01
источник пользователем

голоса
0

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

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

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

 Item Next Prev
   A   B     -
   B   C     A
   C   D     B
   ...

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

Ответил 13/02/2011 в 02:20
источник пользователем

голоса
4

У меня есть идея, несколько похожей на Джессику. Однако, вместо того, чтобы хранить ссылки на следующие и предыдущие пункты сортировки, вы сохраняете порядок сортировки для каждого типа сортировки. Для того, чтобы найти предыдущую или следующую запись, просто получить строку с 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

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

Ответил 13/02/2011 в 03:30
источник пользователем

голоса
0

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

Мой подход будет сериализовать () массив, как только его первые извлекаются, а затем кэш, что в к отдельной области хранения; Является ли это Memcached / APC / жесткий диск / MongoDB / и т.д., и сохраняют свои данные о местоположении кэша для каждого пользователя индивидуально через свои данные сеанса. Фактическая бэкенд хранения, естественно, будет зависеть от размера массива, который вы не вдаваться в подробности о, но Memcached весы большой над несколькими серверами и Монго еще дальше в несколько большей латентностью стоимости.

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

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

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

Ответил 13/02/2011 в 15:47
источник пользователем

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more