![]() |
Модераторы: skyboy, MoLeX, Aliance, ksnk |
![]() ![]() ![]() |
|
Гость_fastkill |
|
||||||||
Unregistered |
Dandik,
безусловно. Однако, как это ни странно, суммарная информация будет одинаковой ![]() Хотя, не совсем. Так как тем больше, то их идентификаторы состоят из большего числа цифр, например, если порядок текущего id юзеров 3 (100, 101,... и т.д), то порядок тем будет, скорее всего, на один больше (по моим субъективным наблюдениям) - то есть четырёхсначное число. Вот здесь и будет проигрыш
но идея заключается также и в том, чтобы при добавлении нового сообщения прибивать соответствующие id-шники тем в поле у юзера. Тогда проблем не будет. Зато появится новая - проигрыш в производительности при добавлении сообщения. Есть, однако, предположение, что удаление id темы из полей юзеров можно сделать одним запросом при помощи строковых функций MySQL (хотя могу ошибаться).
у меня по ходу дела возник дурацкий вопрос ![]() при изпользовании NOT IN (..) в скобках будет в общем случае большой список id-ников. Порядка несколько сотен (предполагаем, что пользователь активно читает форум) Не повлияет ли такая большая размерность списка на скорость выполнения запроса? Sardar оригинально ![]() однако, проблема обсуждаемого нами решения - это не столько проблема памяти при хранении id-шников, сколько проблема потери производительности при выводе списка непрочитанных тем для данного юзера. В том решении всё делается одним SQL-запросом, хотя и тормозным Если я правильно понимаю, надо сначала сформировать из битового представления конкретные id, а потом делать SELECT по NOT IN (список)? |
||||||||
|
|||||||||
Гость_fastkill |
|
|||
Unregistered |
Dandik,
ещё такая идея пришла на ум: в зависимости от степени посещаемости форума среднее число просмотров темы может варьироваться, и чем более популярен ресурс, тем больше будет забиваться поле темы с идентификаторами юзеров, как следствие - дольше будет выполняться поиск при LIKE, то есть имеем снежный ком а если хранить id тем в поле с пользователями, то в этом случае, ввиду того, что человеку физически будет трудно посмотреть слишком много тем (даже отпетому флудеру ![]() |
|||
|
||||
Sardar |
|
|||
![]() Бегун ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 6986 Регистрация: 19.4.2002 Где: Нидерланды, Groni ngen Репутация: 4 Всего: 317 |
В том то всё и суть что нет ![]() Обычно это реализуеться таблицей с составным первичным ключём [<id юзера>,<id мессаги>]. Работает достаточно шустро, до тех пор пока не имеем тысячу пользователей и десятки тысячь сообщений (глянь в подвал форума на первой странице для цифр ![]() В моём способе реализуеться битовое множество id'шников, которое имеет досаточно малый размер. Поле TEXT в MySQL имеет максимальный размер в 2^16 символов, в битах это (2^16)*7 битов, т.е более 450 тысячь идентификаторов. Т.к. мы ограниченны размером, а мессаг может быть гораздо больше, то есть якорь - это мессага от id которой начинаеться отсчёт нашего битового поля. В итоге в профиле каждого юзера есть всего два поля: TEXT - битовое множество и ID - якорь-идентификатор. Задача: имеем список мессаг, нужно узнать которые прочитанны, которые нет. Решение: пробегаемся в цикле для каждой мессаги, ищем её идентификатор в битовом множестве. Если бит установлен - мессага прочитанна. Никаких обращений к БД, только один раз при загрузке профиля грузим и битовое поле. Если мессага имеет id меньший чем у якоря (очень старая мессага), то обьявляем её прочитанной и наоборот, если id больший чем якорь+длинна_битового_множества, (то видать ты давно не сдвигал якорь ![]() По моему должно работать очень эффективно, где самые большие затраты будут на постоянном обновлении большой строки."Но по моему это будет меньше, чем поиск и добавление записей в таблицу "традиционного решения". -------------------- Опыт - сын ошибок трудных © А. С. Пушкин Процесс написания своего велосипеда повышает профессиональный уровень программиста. © Opik Оценить мои качества можно тут. |
|||
|
||||
FastKill |
|
|||
Новичок Профиль Группа: Участник Сообщений: 10 Регистрация: 30.12.2002 Репутация: нет Всего: нет |
хм.. может, чего-то не так понял, но остались вопросы: а если список мессаг, которые предположительно (потенциально) могут быть непрочитанными, очень велик(порядка нескольких сотен, а то и тысяч)? В то время как нам-то надо вывести всего-навсего, допустим, 20 ссылок (если столько наберётся. А так можно и меньше. Если новых нет - выводится "ничего не найдено") на новые сообщения (вернее, на темы с таковыми), плюс, если их реально больше 20, то ссылки на последующие страницы (тоже будут выводиться по 20 штук ссылок)? Правильно ли я понимаю, что в варианте с битовыми полями надо сначала получить список потенциально-непрочитанных тем? |
|||
|
||||
Dandik |
|
||||||
![]() Новичок Профиль Группа: Участник Сообщений: 38 Регистрация: 20.10.2005 Где: Раменское Репутация: нет Всего: нет |
Гость_fastkill,
Действительно, по всеобщему закону сохранения... и время запросов будет равно, но только в том случае, если одновременно будут проверяться все поля пользователей... чего быть не может... Тобишь мы получим например 1000 полей (из таблицы тем) с 10 идентификаторами пользователей или же 10 полей пользователей с 1000 идентификаторами тем. Но проверять мы будет за один раз 1-о поле (1-о из 1000 или 1-о из 10 не важно, всёравно одно). На лицо выйгрыш времени в проверки короткого текстового поля над длинным.
Почему же не будет, ведь id не хранят инф-ю о времени, т.ч. одним этим полем не обойтись...
так не тебе же вводить это всё от руки ![]() Sardar , Отдельную таблицу для реализации данной функции - слишком много, придётся делать параллельный запрос к этой таблице при входе (не считая запрос пользователя)... Я так понимаю, что побитовым представлением ты хочешь укоротить запись списка id тем и все (+ флаг времени обновления, для обновления данного битового текстового поля...Кстати не совсем понятно, какими действиями нужно провоцировать скрипт на обновление, неужели обновлять при каждом заходе...). Так вот, если подобное представление нужно лишь для уменьшения веса указанного выше списка, то почему бы таким образом не укоротить список пользователей (который и так не длинный, т.к. мы выяснили, что тем всегда больше, чем пользователей) В поле каждой темы, в этом случае и сработает главное преумущество - простота обновления (обнуление данного списка). Если я, конено правильно понял, хотя скорее нет, т.к не сталкивася с подобного рода хранением инф-и... если это намного выгоднее, то почему всё хранение id не реализовано таким образом ? Расскажи поподробнее про данный метод, каким образом заполнить и считать поле БД, организованное подобным образом.. |
||||||
|
|||||||
Sardar |
|
||||
![]() Бегун ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 6986 Регистрация: 19.4.2002 Где: Нидерланды, Groni ngen Репутация: 4 Всего: 317 |
Если это было ко мне, то всё не правильно понято ![]() Вообще чем больше мы знаем о природе данных, тем эффективней можно с ними работать. Например если все новые мессаги получают id больший чем старые(что и происходит), то по идентификатору можно отсортировать по "возрасту" список мессаг. Второе, битовое поле это один из очень эффективных способов хранить некое множество обьектов. Обьекты должны быть упорядоченны. Третье, битовое поле описанное мной выше считываеться один раз. Далее по нему можно узнать всё необходимое. При чём храниться оно может в профиле пользователя (там где логин, пароль и прочая инфа), хотя можно и вынести в отдельную таблицу на связи 1:1. Если ещё не понятно, то возьми образно в руку число, это будет твой первый идентификатор(самое старое сообщение). Возьми первый бит битового поля и прибавь его к числу в руке, получили следующий идентификатор. Таким образом прибавляя к "якорю" порядковый номер бита, ты "перемещаешся" по идентификаторам, значение же бита указывает состояние, для нас это (не)прочитанно. Естественно что все операции происходять на скриптах(это побитовый сдвиг, деление и деление по модулю очень быстрые операции ![]() Больше пояснять не буду, если ещё не ясно, то я бессилен ![]()
Зачем мне этот список? Читая обьяснение выше ясно что самое битовое поле это список id'шников мессаг. Задача: выбрать 50 последних не прочитанных сообщений Решение: Найти идентификатор самого последнего сообщения(операция со сложностью O(1) мгновенная) Находим позицию идентификатора в битовом поле От позиции читаем биты "назад", записываем идентификаторы биты которых равны 0(не прочитанно) Когда список наберёт 50 идентификаторов или если битовое поле закончиться, выбираем все идентификаторы из БД. Думаю на этом примере станет ясно ![]() -------------------- Опыт - сын ошибок трудных © А. С. Пушкин Процесс написания своего велосипеда повышает профессиональный уровень программиста. © Opik Оценить мои качества можно тут. |
||||
|
|||||
Stampede |
|
||||||||||
![]() Гносеолог ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 963 Регистрация: 25.4.2005 Где: Calgary, Alberta, Canada Репутация: нет Всего: 144 |
Sardar, все хорошо, но ты забыл одну весчь: признак прочитанности должен сбрасываться, если в теме появляется новое сообщение. Причем у всех. А поскольку мы наперед не знаем, кто эту тему уже читал, то придется сканировать всех! юзеров. К тому же, учитывая, что мы храним данные в хитром битовом формате, то в самом лучшем случае мы напишем хранимую процедуру, а если таковые не поддерживаются, то придется каждого юзера загружать по очереди, расшифровывать битовый массив - и при необходимости выдирать запись о теме и сохранять обратно в базе. Это, извините, работать просто не будет.
Теперь мое предложение. Я считаю, что идеальный формат хранения - это таблица вида:
Теперь оценим количество записей в такой таблице (на примере Винграда). Имеем 50,000 топиков. Каждый топик за все время когда-либо просмотрит, скажем, 100 человек. Это 5 миллионов записей. Не мало, но и не сильно много. Поскольку все поля проиндексированы, то выборки/апдейты будут происходить мгновенно. Но что делать, если пространство у нас ограничено? А очень просто: нам ведь не нужно вести историю от царя Гороха. Я думаю, журнал посещенных страниц за последний месяц будет вполне приемлемым компромисом. Прикидываем: 100 новых топиков в день на 100 юзеров, которые заглянут в него в течение месяца - итого 10,000 записей. Десять тысяч - это совершенно детский размер, и это, учтем, мы считали для такого популятного и активного форума как Винград. Теперь рассмотрим типичные операции: 1. Подсветить на странице прочитанные юзером темы как прочитанные Поскольку тем на странице - ограниченное количество (default=20), то можно легко проитерировать и составить селект вида:
Выполняется за доли секунды. 2. Сбросить признак прочитанности при добавлении в топик нового поста Для всех, кто когда-либо читал данную тему, она должна стать "непрочитанной":
3. При каждом просмотре темы обновлять время последнего просмотра
На самом деле время последнего просмотра - признак необязательный, если мы всего лишь хотим иметь информацию "прочитан/непрочитан". Но уж коль скоро мы заморачиваемся с такой таблицей, то почему бы не добавить и дату. Тогда мы элементарно сможем добавить такие полезные фичи (как на Винграде): - кто сейчас просматривает тему
Логика, конечно, упрощенная (кто заходил за последние 5 минут), но вполне понятная и разумная. - когда и где юзер был последний раз Ну и так далее. Пишу подробно, потому что мне скоро самому предстоит делать форум, так что это для меня нечто вроде чернового спека ![]() Ну и, разумеется, интересно было бы услышать здоровую конструктивную критику ![]() -------------------- "If you want something done right, do it yourself" По секрету: выучить английский - реально! |
||||||||||
|
|||||||||||
Sardar |
|
||||
![]() Бегун ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 6986 Регистрация: 19.4.2002 Где: Нидерланды, Groni ngen Репутация: 4 Всего: 317 |
Мдям, а я в голове держу список почты, обычное мыло, а не список топов на форуме, звиняюсь ![]()
Почему? БД должна уметь сохранять и выдавать строку целиком, в лучшем же случае хранимая процедура, тогда можно обойтисть изменением части строки. А выбрать нужный символ из строки, а затем взять его код и представить битами - это вообще не задача. Подумаем как можно всё таки эффективно прикрутить битовое поле к форуму, состоящему из: подфорумов, содержащих топики, содержащие посты (позже увидим что структура форума не важна). Задача: найти на форуме(таком как этот) все новые топы и свежие форумы. Реализовать кнопку "перейти к первому не прочитанному". Решение: Топик содержит посты, каждый новый пост имеет идентификатор больший чем все другие посты в топе(упорядоченны по возрастанию). Это логично, т.к. посты между топиками не передвигаються (перемещаем топы, не посты). При добавлении постов их идентификаторы всегда max_id+1. Не важно что разница между предпоследним и последним постом в топе может быть больше 1. Тогда берём самый последний пост в топе и проверяем его на битовом поле. Если пост не прочитан, значит топ свежий. Если форум имеет хотя бы один свежий топ, до и форум свежий. Эта вся инфа нужна при листинге форумов и постов. Теперь как перейти к первому не прочитанному сообщению. Достаём последние 100 идентификаторов постов в топе (это первичные ключи, значение сразу из индекса берёться, без обращения к данным). Ищем с конца списка id первого прочитанного поста. Если нашли, то следующий id в списке это первый не прочитанный, к нему и идём Иначе выбираем следующие 100 со смещением от конца. Это редко будет происходить. Мне нравиться идея ![]() -------------------- Опыт - сын ошибок трудных © А. С. Пушкин Процесс написания своего велосипеда повышает профессиональный уровень программиста. © Opik Оценить мои качества можно тут. |
||||
|
|||||
Dandik |
|
|||
![]() Новичок Профиль Группа: Участник Сообщений: 38 Регистрация: 20.10.2005 Где: Раменское Репутация: нет Всего: нет |
Ребят, я вот до сих пор никак не пойму зачем создавать для этой функции новую таблицу, с полями времени, пользователя, когда можно всё сделать в таблице темы... И по сути сам запрос включить в стандартный запрос на выборку тем из БД, тобишь в цикл вывода тем. В этом случае все временные ресурсы будут затрачены на дополнительном условии в выборке тем (проверка поля длинной, как уже было сказано не более 100 id (в основном менее. т.к. подразумивается частое обнуление поля)). Кстати само обнуление тоже не потребует отдельного запроса, а просто лишь дополнит UPDATE темы при её при обновлении. Отсюда получим, что реализация задачи не потребует ни одного лишнего запроса, ни создания отдельной таблицы...
Вот расскажите мне, тёмному, в чём могут быть минусы данного подхода? |
|||
|
||||
![]() ![]() ![]() |
Правила форума "PHP" | |
|
Новичкам:
Важно:
Внимание:
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, IZ@TOP, skyboy, SamDark, MoLeX, awers. |
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | PHP: Общие вопросы | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |