Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 2014.01.26;
Скачать: [xml.tar.bz2];

Вниз

Пагинация как ВКонтакте. Как?   Найти похожие ветки 

 
ProgRAMmer Dimonych ©   (2013-08-07 02:19) [0]

Исходные данные

* Большая таблица в БД на сервере.
* Клиентское приложение, отображающее содержимое таблицы.
* Ввиду больших объёмов данных загрузка производится по мере необходимости небольшими порциями (постранично).
* Отображаемые данные сортируются и/или фильтруются по одному или нескольким полям.
* Записи могут добавляться/изменяться/удаляться другими пользователями, работающими параллельно.
* Пользователей, работающих одновременно с таблицей, относительно немного (2–3); таких таблиц — пара десятков.
* Для конкретики: PHP+MySQL на сервере, HTML+JS на клиенте, взаимодействия через HTTP (AJAX).

Требуется

1. Подгрузка данных по частям.
2. Обновление уже загруженных данных (при добавлении/редактировании/удалении).

Что пробовал/обдумывал

а) Простая выборка типа "LIMIT 250, 10", т.е. с 250-й записи 10 штук. Отмёл сразу, потому что (1) собьётся, когда в таблицу добавятся новые записи, и (2) уложит на лопатки сервер на последних страницах.
б) В запросе на получение новой порции данных передавать значения полей, по которым идёт сортировка, из последней полученной записи. Возвращать в ответ записи после соответствующей. Реализовал. Выяснилось, что такое поля, по которым идёт сортировка, необязательно однозначно идентифицируют запись. В результате некоторые записи вываливаются из перечисления.
в) Передавать ID последней принятой записи. Возвращать в ответ записи после соответствующей. Реализовал. Работает красиво. Но поломается, если удалить запись с таким ID: информация, по которой можно отфильтровать уже переданные записи, будет утеряна.
г) Вместо удаления записи скрывать её от перечисления, пока кто-нибудь работает с этой таблицей. Обдумал. Определить момент окончания работы с таблицей невозможно: например, при обрыве связи между клиентом и сервером.
д) Завести таблицу, в которой сохранять информацию для каждого пользователя о том, какие изменения происходят в наборе записей, с меткой времени. В запросе дополнительно передавать метку времени последнего обновления. Если опорная запись (с ID из запроса) уже удалена, возвращать пустой набор, повторять запрос с ID предшествующей записи. Обдумал. Громоздковато.

Гуглёж выдаёт тысячи ссылок на статьи по примитивной пагинации (без обновления), такое ощущение, что я — единственный человек, перед которым поставили задачу сделать «как в лучших борделях Парижа». Или единственный, кто с этой задачей не может справиться.

Вопрос

Как вообще это правильно реализуется?


 
Eraser ©   (2013-08-07 04:24) [1]


> Пользователей, работающих одновременно с таблицей, относительно
> немного (2–3);

тогда почти как угодно можно делать )


 
Обычный порошок   (2013-08-07 05:31) [2]

а) Простая выборка типа "LIMIT 250, 10", т.е. с 250-й записи 10 штук. Отмёл сразу, потому что (1) собьётся, когда в таблицу добавятся новые записи, и (2) уложит на лопатки сервер на последних страницах.

1. Ничего и никуда не собъется когда в таблицу добавят новые записи.
если ты выбрал первые десять, затем кто-то вставил новую, которая в твоем запросе попала бы в первую десятку, то на второй странице ты получишь второй десяток, но с десятой "старой"  записи а не с одиннадцатой.

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

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

остальные варианты б-д - заведомо неживые.


 
Anatoly Podgoretsky ©   (2013-08-07 10:58) [3]

> ProgRAMmer Dimonych  (07.08.2013 02:19:00)  [0]

А ты используй >= ID


 
[ВладОшин] ©   (2013-08-07 11:44) [4]

ниче не надо


> почти как угодно можно делать

+

> Обычный порошок   (07.08.13 05:31) [2]

особеннно

> остальные варианты б-д - заведомо неживые.


надо юзерам дать понять, что это общие данные, меняются постоянно.

зы
достали :)
- Дай оплаты на %Фирма% по %ГруппеА%
- На
Пока сам посмотрит, пока начальнику перешлет, пока 5-10..
- А вот ваш %Фио% дает в %Разрезе% - у вас не сходятся..
- так он дал тока что, а я те дал уже 40 минут назад! За 40 минут уже два платежа из банка плюхнулись!!

Выборка потенциально не верна уже на следующую секунду после получения!!!


 
antonn ©   (2013-08-07 11:56) [5]

выборка на дату-время делается же

а вообще такое лучше спрашивать на форумах по вебу, типа php.ru


 
ProgRAMmer Dimonych ©   (2013-08-07 17:04) [6]

> [2] Обычный порошок   (07.08.13 05:31)
> 1. Ничего и никуда не собъется когда в таблицу добавят новые
> записи.
> если ты выбрал первые десять, затем кто-то вставил новую,
> которая в твоем запросе попала бы в первую десятку, то
> на второй странице ты получишь второй десяток, но с десятой
> "старой"  записи а не с одиннадцатой.

Отображение не постранично, а добавлением новых к ранее загруженных, как в новостной ленте ВКонтакте. Если я получаю десятую старую запись, она продублируется — этого быть не должно. Фактически ведь требуется не «дай мне страницу такую-то», а «дай мне следующие N записей»

> [2] Обычный порошок   (07.08.13 05:31)
> 2. на лопатки никто никого не уложит, так как если делать
> выборку без лимит и старт то сервер будет еще задумчивей.

Выборки вида "LIMIT 1000000000, 10" в MySQL работают неэффективно, т.к. сначала производится выборка 1000000010 записей, а потом миллиард отбрасывается. Полагаю, в других СУБД ситуация не лучше.

> [3] Anatoly Podgoretsky ©   (07.08.13 10:58)
> А ты используй >= ID

Направление сортировки может не совпадать с направлением возрастания ID. Например, при сортировке пользователей по алфавиту.

> [4] [ВладОшин] ©   (07.08.13 11:44)
> Выборка потенциально не верна уже на следующую секунду после получения!!!

Это всё очень хорошо понятно. Но (а) требования есть требования, (б) ВКонтакте это реализовано и даже под нехилой нагрузкой, зачем считать невозможной реализацию под меньшей нагрузкой с неспециализированной СУБД?

> [5] antonn ©   (07.08.13 11:56)
> выборка на дату-время делается же

Этой мысли не понял. Можно подробнее?

> [5] antonn ©   (07.08.13 11:56)
>а вообще такое лучше спрашивать на форумах по вебу, типа php.ru

Как уже неоднократно отмечалось участниками форума, здесь есть специалисты, которые неплохо разбираются во многих областях. Тем более, что вопрос применим не только к Веб: есть БД, есть требование к отображению данных из неё и ограничения на использование сети (только короткие сеансы клиент-сервер a la HTTP). Ну и потом на других форумах (даже вроде бы неплохих и раскрученных типа stackoverflow и т.п.) иной раз ответы на элементарные вопросы заставляют волосы на голове шевелиться. Чего ожидать от задач посложнее?


 
[ВладОшин] ©   (2013-08-07 17:07) [7]


> ВКонтакте это реализовано

не юзаю
А как там реализовано, если не секрет/не влом?
т.е. что там происходит в ситуации

если ты выбрал первые десять, затем кто-то вставил новую, которая в твоем запросе попала бы в первую десятку

то что он делает?


 
ProgRAMmer Dimonych ©   (2013-08-07 17:17) [8]

> [7] [ВладОшин] ©   (07.08.13 17:07)

В ленте новостей отображаются посты «друзей» (фильтрация). По убыванию даты/времени добавления (сортировка). При загрузке страницы подгружается около десятка записей. При прокрутке страницы внизу добавляются более старые записи. Те, которые уже загружены, никуда не исчезают. Если «друг» удалил запись — из ленты новостей она исчезает (остальные, разумеется, остаются). Если отредактировал — соответственно, обновляется. Если кто-то из «друзей» создал новый пост у себя на странице, он появится в начале списка (т.е. в порядке сортировки).

На других страницах есть сортировка не только по дате добавления — т.е. необязательно направление сортировки совпадает с таковым для ID.


 
Плохиш ©   (2013-08-07 17:23) [9]

при выборке сортировка по убыванию
выборка необходимого количества первых записей
при прокрутке "необходимое количество" увеличивается на энную величину.

PS. Пора нанять программиста.


 
ProgRAMmer Dimonych ©   (2013-08-07 17:29) [10]

> [9] Плохиш ©   (07.08.13 17:23)
> при выборке сортировка по убыванию
> выборка необходимого количества первых записей
> при прокрутке "необходимое количество" увеличивается на энную величину.

> PS. Пора нанять программиста.

Программист уже здесь и у него вопрос: как быть, если между загрузкой N-1-й и N-й порций добавились записи, которые отправляются в начало списка? Пожалуйста, читайте вопрос внимательнее или пишите ответ подробнее.


 
ProgRAMmer Dimonych ©   (2013-08-07 17:30) [11]

> [9] Плохиш ©   (07.08.13 17:23)

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


 
Плохиш ©   (2013-08-07 17:42) [12]

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


 
Sha ©   (2013-08-07 17:49) [13]

> ProgRAMmer Dimonych

Сортировка по N+1 полю. Для уникальности последним полем всегда включается ID.
Помним значения этих полей для первой и последней показаной записи.
При прокрутке - селект 10 первых записей, больших или меньших запомненной.


 
ProgRAMmer Dimonych ©   (2013-08-07 17:50) [14]

> [12] Плохиш ©   (07.08.13 17:42)
Если считаешь, что вконтакте делает как-то по-другому, описанный тобой функционал, то попытайся купить/украсть у них их волшебную палочку.

Проверил в Firebug: при подгрузке более старых записей объём получаемых от сервера данных не возрастает. Следовательно, передаются не все данные от начала до текущей позиции, а только те, которые действительно необходимо передать. Что логично, иначе заDDoSить Контактик было бы проще простого.


 
ProgRAMmer Dimonych ©   (2013-08-07 18:06) [15]

> [13] Sha ©   (07.08.13 17:49)

Обдумал. Это объединение решений (б) и (в) из [0]. Похоже, действительно обеспечивает решение первой части задачи — подгрузку по частям. Если других идей ни подскажут, так его, видимо, и придётся реализовывать. Попробую соорудить прототип.

Вторая часть (обновление уже загруженной части) вроде легче поддаётся решению.


 
Eraser ©   (2013-08-07 18:09) [16]


> ProgRAMmer Dimonych ©   (07.08.13 18:06) [15]


> Обдумал.

по php и веб программированию книжку почитай, а то так "обдумывать" много чего придется.

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


 
ProgRAMmer Dimonych ©   (2013-08-07 18:34) [17]

> [16] Eraser ©   (07.08.13 18:09)

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


 
Inovet ©   (2013-08-07 18:39) [18]

> [11] ProgRAMmer Dimonych ©   (07.08.13 17:30)
> каждый раз подгружаются все от начала списка до текущего
> положения прокрутки

Вроде бы только новые.


 
antonn ©   (2013-08-07 18:43) [19]


> Этой мысли не понял. Можно подробнее?

ну я в том смысле, что документы такого плана имеют дату формирования, поэтому просто сказать "у вас отчеты неверные" нельзя, на дату формирования они были актуальными. но это оффтоп


> Как уже неоднократно отмечалось участниками форума, здесь
> есть специалисты, которые неплохо разбираются во многих
> областях. Тем более, что вопрос применим не только к Веб:
>  есть БД, есть требование к отображению данных из неё и
> ограничения на использование сети (только короткие сеансы
> клиент-сервер a la HTTP). Ну и потом на других форумах (даже
> вроде бы неплохих и раскрученных типа stackoverflow и т.
> п.) иной раз ответы на элементарные вопросы заставляют волосы
> на голове шевелиться. Чего ожидать от задач посложнее?

Тут не нужна сложность, тут больше нужны молодые-свежие умы не загнанные в рамки своего опыта и могущие "прогнуться" под желания пользователя, желающие сделать костыли (как например счетчик "кол-во пользователей на сайте" - это костыль, но он сейчас есть много где). Ну под веб с динамикой в принципе понятно - аякс и что нибудь для работы с ним (например jquery). А вот что ты собираешься обновлять - уже сильно ударит по разработке, тебе надо будет делать запрос перед сохранением редактирования и периодически. При этом не допускать перезатирания в процессе редактирования. Аяксом можно отправлять id последнего загруженного, скриптом на сервере делать выборку более поздних id и отдавать клиенту, там больше вопрос о том как визуально потом это показывать. Тут не будет элегантных решений, будет громоздко, будут дикие костыли, без них не обойтись (это же http), "правильного" решения тут нет, каждый изголяется как может.


 
ProgRAMmer Dimonych ©   (2013-08-07 18:47) [20]

> [18] Inovet ©   (07.08.13 18:39)

Да, уже проверили.

> [19] antonn ©   (07.08.13 18:43)

Интересная мысль, спасибо. Главное сейчас взять от неё ровно столько, чтобы решить задачу и в то же время не перейти на г&$новкод :)


 
Обычный Порошок   (2013-08-07 19:10) [21]

Отображение не постранично, а добавлением новых к ранее загруженных, как в новостной ленте ВКонтакте.

Какая разница?
У тебя в любом случае размер и содержание новой порции зависит от ордер бая в запросе.

Значит уже загруженное в браузер не грохаем,
выборку делаем where только новые,
и при желании режем это новое через тот же лимит.
Вот и все.

Осталось научиться отличать новые от неновых сообщений.


 
Inovet ©   (2013-08-07 19:16) [22]

А не сам ВК шлёт всем активным сессиям? Как-то уж больно оперативно оно обновляется.


 
Обычный Порошок   (2013-08-07 19:23) [23]

так не бывает.
это клиент сам очень часто спрашивает обновления


 
ProgRAMmer Dimonych ©   (2013-08-07 22:04) [24]

> [21] Обычный Порошок   (07.08.13 19:10)
> Значит уже загруженное в браузер не грохаем,
> выборку делаем where только новые,
> и при желании режем это новое через тот же лимит.
> Вот и все.

> Осталось научиться отличать новые от неновых сообщений.

Ну так внезапно проблема и заключалась только лишь в том, чтобы правильно выбрать именно «новые» (в общем случае — «следующие») данные. Вопрос касался того, каким должен быть протокол обмена: что передаёт клиент, как интерпретирует сервер и как это сделать без излишеств. И варианты (а)–(д) отличаются как раз этим. Как выглядит SELECT и как использовать WHERE, ORDER BY и LIMIT — это общеизвестно и прекрасно гуглится.


 
Обычный Порошок   (2013-08-07 22:10) [25]

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

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


 
ProgRAMmer Dimonych ©   (2013-08-08 12:28) [26]

> [25] Обычный Порошок   (07.08.13 22:10)

Кроме сортировки по времени некоторые таблицы сортируются по другим критериям, записи ВКонтакте приводились как пример. Метка времени — недостаточный критерий, потому что может повторяться. В сочетании с IDшником — да, но это уже было решено где-то между [13] и [15].


 
Обычный порошок   (2013-08-08 12:43) [27]

проблема и заключалась только лишь в том, чтобы правильно выбрать именно «новые» (в общем случае — «следующие») данные. Вопрос касался того, каким должен быть протокол обмена:

Если проблема в выборке новых, то вопрос по протоколу пока вообще не актулен.

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


 
Eraser ©   (2013-08-08 13:39) [28]

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


 
ProgRAMmer Dimonych ©   (2013-08-08 19:32) [29]

> [27] Обычный порошок   (08.08.13 12:43)

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

> [28] Eraser ©   (08.08.13 13:39)

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

-----

В целом мне уже по этой задаче полегчало :)



Страницы: 1 вся ветка

Форум: "Прочее";
Текущий архив: 2014.01.26;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.56 MB
Время: 0.003 c
15-1367048392
brother
2013-04-27 11:39
2014.01.26
Химтрейлы, химиотрассы


15-1375766820
MonoLife
2013-08-06 09:27
2014.01.26
Принтер для печати на "толстеньких" бланках


15-1375442738
Павиа
2013-08-02 15:25
2014.01.26
Десантники отмечают день ВДВ


15-1375861462
Empleado
2013-08-07 11:44
2014.01.26
Android в XE5?


15-1375968384
[ВладОшин]
2013-08-08 17:26
2014.01.26
как на С будет?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский