Временные идентификаторы (и записи) в таблице БД

Qwerty

Новичок
Временные идентификаторы (и записи) в таблице БД

Это не тема про поиск ошибки, это поиск пути решения задачи (доводить до кода не потребуется, только алгоритм).
К сожалению (или к счастью) одна подобная, не моя, тема была закрыта из-за опасной формулировки и не менее опасного для широкой публики обсуждения, я же постаряюсь здесь описать задачу максимально политкорректно. :)
Предполагается, что работать мы будем с базой данных, поэтому для темы и выбран этот раздел. Кроме того, в нем же была расположена злополучная закрытая тема. Однако предложения без использования БД приветствуются.
Итак, достаточно для вступления.

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

Почему выбрана именно временная уникальность? Потому что кодов выдается очень много, требуется генерировать новый код при каждой загрузке страницы. Подавляющее большинство из них даже никак не используется и становится ненужным по истечении своего времени жизни (удаляются).
Таким образом, если в виде этого кода будет использоваться идентификатор auto_increment primary key, то его значение очень быстро перевалит, скажем, за 1000000 и будет увеличиваться в течение всего времени жизни сайта, тогда как реально в таблице будет существовать одновременно только около 1000 записей. Помня, что выдаваемый пользователю код должен быть максимально коротким, лучше бы выдать 3-значное число для указания одной из этих 1000 реально существующих записей, а не 6-7-значное, равное primary key, для указания номера записи за всё время существования сайта.

Так как вмешиваться в работу auto_increment и использовать уже использовавшиеся идентификаторы для нас табу (из-за этого и была закрыта вышеупомянутая тема), придется, вероятно, для хранения кода ввести дополнительное поле code (хотя мой варинт был с вмешательством в auto_increment, приводить не буду, опять попаду в немилось :) ).

Так вот. Интересуют предложения по реализации.
Если что-то осталось неясным, я напишу подробнее.
На самом деле сложно было всё это сформулировать. Возможно, получилось не совсем ясно...
 

Фанат

oncle terrible
Команда форума
Задачу описываем не абстрактно, а конкретно и подробно.

-~{}~ 05.09.07 15:00:

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

Qwerty

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

Уникальный код должен генерироваться для каждого нового сочетания пользователь + get-параметр. Get-параметр указывает, с какого сайта был переход, это сайт партнера. Публикуемый код является частью текста (префикса), который необходимо отправить через SMS для предоставления некоторой услуги.
Например:
http://site?g=3 может сгенерировать код 1234 для одного пользователя, но 1235 для следующего.
Почему нельзя сделать фиксированный текст для каждого партнера, просто включающий его id. Это защита от недобросовестных партнеров, которые могут опубликовать данный номер и текст в другом месте, описать услугу иначе и обманывать клиентов. Поэтому генерируем для них эти динамические префиксы.

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

Могу подробнее...
 

Mols

Новичок
Хм... ну блин... как вариант могу предложить следующее...
Юзать таки автоинкремент, а пользователю в качестве ключа - посылать например остаток от деления автоинкремента на 10 000, получишь гарантировано уникальные значения (ведь не больше тысячи в активном состоянии). И сократится длина отправляемого кода... до 4 символов... Кроме того этот подход быстро масшабируется... можно просто посылать остаток от деления на большее число...если вдруг число посетителей резко вырастет.

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

Qwerty

Новичок
...посылать например остаток от деления автоинкремента на 10 000, получишь гарантировано уникальные значения (ведь не больше тысячи в активном состоянии)...
Не гарантировано, к сожалению.
Я упустил в описании один момент. Время жизни кода составляет несколько часов только в случае, если он не был использован (активирован). При получении SMS с этим кодом время жизни продляется, скажем, на три дня. Т.е. теоретически некоторые коды могут жить очень долго.

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

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

cDLEON

Онанист РНРСlub
Букв много. А написано не понятно и путующе.
 

kruglov

Новичок
[sql]
select t1.id-1 from
table as t1
left join
table as t2
on t1.id = t2.id + 1
where isnull(t2.id) and t1.id>1
order by t1.id
limit 1
[/sql]

-~{}~ 05.09.07 21:52:

При получении SMS с этим кодом время жизни продляется
А если код не продлился, удалился, выдался другому человеку, а предыдущий владелец взял и прислал SMS?
 

Mols

Новичок
Автор оригинала: Qwerty
При получении SMS с этим кодом время жизни продляется, скажем, на три дня. Т.е. теоретически некоторые коды могут жить очень долго.
я так понял, что проблема именно в том, что в приходящем СМС не должно быть длинных кодов... но ведь сам ответ ответ ждёте то всего пару часов.. после получения СМС зачем вам этот урезанный ИД ? потом юзайте полный ИД.... уже на серве и для своих целей.
Если всётаки это не подходит.... ну заведите себе табличку. с парой полей. Одно `id` второе `condition`.
Сделайте какую нить функцию МуСКЛ, которая будет дёргать первый ид с подходящим `condition` И придумайте как приводить поле `condition` в соответствующие состояния... можно ещё третье поле добавить... типа timestamp, для отслеживания устаревания... в общем разберётесь. Хорошо бы конечно не привязыватся к такому малому числу... 1000... заложите сразу до 5 символов. В табличку пока суньте 999... если охота конечно... но в функцию дергающую свободный ИД - добавьте условие, что если свободный ИД не найден - добавить ещё запись. и вернуть её ИД.

Ну а дельше дело техники.. функции МуСКЛя можно использовать и в инсертах и в апдейтах.
Думаю я бы так сделал
 

Qwerty

Новичок
kruglov
Здорово, запрос мне понравился! Я не мог придумать, как найти первый незанятый идентификатор.
Это с теоретической точки зрения. На самом-то деле, выполнение такого запроса с left join, наверное, не очень-то быстрое... Правда, если записей, как в нашем случае, всего 1000...
Вот и ответ на вопрос, заданный в теме auto_increment, погоди!.

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

-~{}~ 06.09.07 05:45:

Mols, kruglov
Я в своем варианте делал так: не удалял ставшие ненужными записи, а помечал как неактивные (таблица при этом сильно не разрастается). При этом выбирать первую неактивную запись гораздо быстрее, чем делать хитрое пересечение таблиц (но запрос kruglov-а меня порадовал, учиться соображать мне надо). Так вот, находим первую неактивную запись и делаем ее update. Если неактивных нет, то только тогда новый insert.

Я не вижу ничего запретного в таком повторном использовании идентификаторов в данном случае. Главное ведь что? Чтобы делать это осмысленно, а не как в примере, который критикуется здесь. Ответ "так делать нельзя, потому что нельзя" подходит для новичков в PHP, но новички форума таковыми могут и не являться.
 

Gas

может по одной?
kruglov
только может SELECT t1.id + 1 ?

Qwerty
я бы наверное не парился и в таблицу (код, time_expire, index(time_expire) и index(код)) сразу нагенерил коды от 100 до 99999 и забыл про лишние проверки и insert,delete.
 

kruglov

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

Qwerty

Новичок
Gas
Я уже проверил запрос прежде, чем писать восторженный коммент. :)
 

Mols

Новичок
У меня вопрос к автору. К чему эта ветка ? У Вас вполне нормальное решение с апдейтом устаревших строк... в чём проблема то ? зачем наворачивать условия в постановке задачи, а потом восхищаться решениями которые нарушают эти условия ?
Или я чего то не понял, или Вы просто описали не ту задачу
которую хотите решить.
 

Qwerty

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

Спасибо за участие в обсуждении.

P.S. Расписано так всё подробно потому, что модератор потребовал.
 
Сверху