0
<< предыдущая заметкаследующая заметка >>
06 марта 2010
Распухла таблица логинов...

Собственно говоря, у меня в дальних планах было привести ее в порядок. Ситуация в следующем: в таблице заводится учетная запись для КАЖДОГО посетителя. Так надо.

Но там куча полей для регистрации (имя, емайл, пароль, логин и т.п.), которыми большинство случайных посетителей никогда не воспользуется, поскольку не оставляют комментарии и не регистрируются. На данный момент учетных записей: 85662, из них пустых: 79089 (а если не считать поле lj, которое автоматом определяется, то и вовсе пустых 81445).

Варианта два:

1) Завести отдельную таблицу, куда записывать только личные данные пользователей, а в основной таблице оставить всего два поля int: собственно номер посетителя и, если не 0, ссылка на другую таблицу, где хранятся регистрационные поля.

2) Для «пустых» посетителей не хранить вообще учетной записи, а тупо пропускать нумерацию. Пусть останутся только заполненные записи: 80000,80007,80035, а если посетитель с присвоенным номером 80001 оставит о себе какую-то личную информацию, всегда можно завести учетную запись 80001.

Лично мне больше нравится вариант 2, но я не понимаю, как дать команду MySQL узнать, на чем остановился первичный индекс и увеличить его на единицу, не добавляя самой записи. И не возникнет ли сбоев, если два новых пользователя зайдут в одну секунду, и обоим будет в куку выдан одинаковый номер 80001 без записи в базу.

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

Что посоветуете?

<< предыдущая заметка следующая заметка >>
пожаловаться на эту публикацию администрации портала
архив понравившихся мне ссылок
Оставить комментарий
Windows Opera
1
0
anonymous
Этот человек не загрузил свой юзерпик, и я подобрал ему этот. Человек, пишущий такое, должен именно так выглядеть, верно?
Чистить раз в год. Миллиона пользователей там точно не будет. Если начнет тормозить, прикрутить индексы.
Windows Opera
0
0
anonymous
Этот человек не загрузил свой юзерпик, и я подобрал ему этот. Человек, пишущий такое, должен именно так выглядеть, верно?
Но вот "синхронизировать" первичный ключ в двух таблицах -- это очень плохая идея. Будут шальные глюки.
Windows Opera
0
0
{name}
Этот человек не загрузил свой юзерпик, и я подобрал ему этот. Человек, пишущий такое, должен именно так выглядеть, верно?
Я бы начал с чистки. А там видно будет.
Windows Opera
1
0
Wot
Этот человек не загрузил свой юзерпик, и я подобрал ему этот. Человек, пишущий такое, должен именно так выглядеть, верно?
ну во первых зачем это все ?
- пустые поля, если varchar места много не занимают
- при наличии индекса на производительность не влияют
- было бы на 2 порядка больше - можно было бы потратить минут 10 на подумать, а так - минуты жалко

во-вторых, так все таки не делается.
- должен быть один id для пользователя и он на автоинкременте.
- если хочется вынести прочие данные в отдельную таблицу то там использовать тот же значение ключа, но без инкремента.
- цеплять ее через select * from t1 left join t2 on (t1.id=t2.id) - тогда будут NULL во всех дополнительных полях если нет записи в t2
- все это доп гиморрой в коде и он не стоит выгоды

в-третьих можно делать как считаешь нужным - свои грабли они ближе к телу. А следущее значение меняется через ALTER TABLE t2 AUTO_INCREMENT = value;
Mac Firefox
1
0
inetd
Этот человек не загрузил свой юзерпик, и я подобрал ему этот. Человек, пишущий такое, должен именно так выглядеть, верно?
В варианте 2) напрашивается реализация через "sequences". MySQL в явном виде не поддерживает sequences, но их можно имитировать через отдельную таблицу с одной записью и единственным полем -- последним выданным id.

Cоздание:

CREATE TABLE sequence (id INT NOT NULL);
INSERT INTO sequence SELECT MAX(id) FROM accounts;

Получение нового id:

UPDATE sequence SET id=LAST_INSERT_ID(id+1);
SELECT LAST_INSERT_ID(); /* или через mysql_insert_id() */

Получение нового id будет атомарно в любом случае (два пользователя не могут получить одинаковые id), потому что обновление максимального id и его получение происходят за один запрос. LAST_INSERT_ID() / mysql_insert_id() просто возвращают ранее сохранённое (и уникальное для сессии) значение.
Linux Firefox
 Москва
1
0
LLeo
Этот человек не загрузил свой юзерпик, и я подобрал ему этот. Человек, пишущий такое, должен именно так выглядеть, верно?
Проблема в том, что заход нового посетителя - одна из самых серьезных нагрузок. Хотя бы потому, что это проявляется в пиковом режиме. Представьте, что какой-то ваш пост по какой-то случайности вдруг попал сегодня во все топы и обсуждается всюду. И к вам в дневник зашли не 30 обычных зарегистрированных френдов, а половина интернета.

Поэтому если процедуру регистрации нового посетителя можно провести как можно быстрее и безболезненней - это надо сделать.

У меня были надежды, что удастся обойтись вообще без записи в базу. Но, видно, пустые надежды.
Windows IE
0
0
sobomax
Этот человек не загрузил свой юзерпик, и я подобрал ему этот. Человек, пишущий такое, должен именно так выглядеть, верно?
Получение sequence это не запись в базу, вернее не совсем запись. Выполняется оно by design намного быстрее чем обычный INSERT или UPDATE, я думаю тысячи, если не десятки тысяч в секунду на современном железе не проблема, ну и отсутвие данного ID в индексе таблицы поможет со скоростью выборки существующих и вставки новых данных. Так что такой путь оптимизации вполне возможен и уместен.
Nokia-E90 Safari
 Москва
0
0
LLeo Nokia
Этот человек не загрузил свой юзерпик, и я подобрал ему этот. Человек, пишущий такое, должен именно так выглядеть, верно?
а как это? Я что-то не улавливаю
Windows IE
0
0
sobomax
Этот человек не загрузил свой юзерпик, и я подобрал ему этот. Человек, пишущий такое, должен именно так выглядеть, верно?
В mysql все немного через ж, там есть внутренний auto-increment (аналог объекта sequence в других базах). Напрямую он не доступен, однако его можно достать через stored function + таблицу из одной записи. Я там сслочку уже кидал на пример реализации такой функции. Использование подобного sequence весьма просто - "SELECT xxx_nextval()" чтобы атомарно получить новое уникальное значение для данной сессии, или "SELECT xxx_currval()" когда надо вытащить уже полученное ранее значение. Также nextval/currval можно использовать в INSERT/UPDATE, например: "INSERT INTO users (id, name) VALUES (users_currval(), 'Vasia Pupkin')".
Mac Firefox
0
0
inetd
Этот человек не загрузил свой юзерпик, и я подобрал ему этот. Человек, пишущий такое, должен именно так выглядеть, верно?
Да, совсем без записи в базу не обойтись.

Если не хранить всех посетитителей, то номер последнего придётся хранить в любом случае. Как иначе можно быть уверенным в том, что новый id уже не выдавали раньше?

А хранить последний id нужно не абы как, а обеспечив безопасную операцию получения/увеличения. То есть, именно в таблице, со всеми блокировками, которые предоставляет база данных.

Как-то так.

И, присоединяясь к комментарию sobomax, я бы не стал волноваться о производительности в этом варианте. Это в любом случае эффективнее, чем то, что есть сейчас. Т.е. поддерживать индекс в очень рыхлой таблице -- куда большие накладные расходы при наплыве новых посетителей, чем простое увеличение поля в однострочной таблице.
Windows IE
0
0
sobomax
Этот человек не загрузил свой юзерпик, и я подобрал ему этот. Человек, пишущий такое, должен именно так выглядеть, верно?
Ээээ, сорри я признаться кажется забыл что в мускле последовательностей встроенных не реализованно. Пользование правильными транзакционными БД (postgresql) развращает. Впрочем реализация счетчика последовательности на базе таблицы из одной записи вполне может оказаться по скорости сравнима с тем что делается специальными средствами в других местах - апдейты в mysql весьма быстрые, особенно если тип таблицы myisam. Вот тут рецепт как реализовать sequence() таким образом:

http://forums.mysql.com/read.php?61,143867,244029#msg-244029

Быстрый тест на стареньком четырехмоторном сервере p4-based xeon показывает вполне приличную производительность порядка 6,000 вызовов R_ObjectId_nextval() в секунду.
Mac Firefox
0
0
inetd
Этот человек не загрузил свой юзерпик, и я подобрал ему этот. Человек, пишущий такое, должен именно так выглядеть, верно?
И именно поэтому я этот объект и предлагаю. ;) Точнее его эмуляцию средствами MySQL.

То была попытка объяснить, почему совсем без записи в базу не обойтись.
Mac Firefox
0
0
inetd
Этот человек не загрузил свой юзерпик, и я подобрал ему этот. Человек, пишущий такое, должен именно так выглядеть, верно?
Минимальную реализацию sequence я уже привёл. А то, что по ссылке -- это ужас какой-то. Stored function + insert + delete + user variable? Нет, спасибо :)
Mac Safari
0
0
{name}
Этот человек не загрузил свой юзерпик, и я подобрал ему этот. Человек, пишущий такое, должен именно так выглядеть, верно?
Функция удобна тем что при ее использовании проще будет потом портировать код на другой сервер БД, постгрес или оракл какой-нибудь. :)
Windows Opera
1
1
gryzchick
Этот человек не загрузил свой юзерпик, и я подобрал ему этот. Человек, пишущий такое, должен именно так выглядеть, верно?
Вообще, СУБД не касается, есть ли в поле запись или нет. Место резервируется в любом случае. Когда требуется выбрать, например, запись под номером 78300, она не парсит подряд весь файл, в котором находится искомое, а вычисляет смещение в байтах, на котором находится искомая строка. Даже если все 78299 записей до этой пусты, СУБД все равно начнет читать с одной и той же позиции в файле.
Windows Firefox
2
0
{name}
Этот человек не загрузил свой юзерпик, и я подобрал ему этот. Человек, пишущий такое, должен именно так выглядеть, верно?
№1 куда как проще, следовательно правильнее
Windows Opera
1
0
tupitochka
Этот человек не загрузил свой юзерпик, и я подобрал ему этот. Человек, пишущий такое, должен именно так выглядеть, верно?
+1
Linux Firefox
 Москва
0
0
LLeo
Этот человек не загрузил свой юзерпик, и я подобрал ему этот. Человек, пишущий такое, должен именно так выглядеть, верно?
Проще - на каком этапе? На этапе проектирования или переделки готового движка? С переделкой всех частей и созданием модулей для апгрейда баз у других пользователей движка?
Windows Opera
0
0
tupitochka
Этот человек не загрузил свой юзерпик, и я подобрал ему этот. Человек, пишущий такое, должен именно так выглядеть, верно?
Таблицы типа InnoDB обеспечивают безопасное выполнение транзакций. Транзакция гарантирует отсутствие наложений.
Windows Opera
3
0
tupitochka
Этот человек не загрузил свой юзерпик, и я подобрал ему этот. Человек, пишущий такое, должен именно так выглядеть, верно?
Цитирую по книге: "наличие большого количества нулевых значений в базе данных - плохая практика. Большинства таких проблем можно избежать, воспользовавшись иным подходом к проектированию."

всего комментариев: 20

<< предыдущая заметка следующая заметка >>