У меня есть таблица пользователей, пользовательский идентификатор является общедоступным. Но я хочу запутать количество зарегистрированный пользователь и тенденции проекта, поэтому я не хочу иметь общедоступные индексы увеличения.
Когда создается новый пользователь, я хочу найти случайный целочисленный номер, который больше определенного числа и который еще не находится в базе данных.
Наивный код:
<?php
$found = false;
while(!$found) {
$uid = rand(1000000000,4294967295) // find random number betwen minimum and maximum
$dbh->beginTransaction();
// check if user id is in use, and if not insert it
if($dbh->query("SELECT * FROM users WHERE uid = $uid")) {
$dbh->exec("INSERT INTO users (uid) VALUES ($uid)");
$found = true;
}
$dbh->commit();
}
// we just got our new uid ...
?>
Это будет работать, однако может стать неэффективным. Правда, что существует большой диапазон, и вероятность попадания неиспользованного uid высока. Но что, если я хочу использовать меньший диапазон, потому что я не хочу иметь длинные идентификаторы пользователей?
Пример моих проблем:
- 60% всех идентификаторов пользователей используются
- вероятность попадания неиспользуемого uid 0.4
- первая попытка имеет 0,4% успеха
- если 1-ую неудачную, вторая попытка имеет 0,6 * 0,4 вероятность
- так что с максимум двумя попытками у меня есть 0,4 + 0,6 * 0,4 возможности (это правильно?)
Итак, один из способов оптимизации - это то, что пришло мне в голову:
- найдите случайное число, проверьте, если его свободный, если нет, увеличьте его на 1 и повторите попытку и т.д.
- если максимальное число нажато, продолжите с минимальным числом
Это должно дать мне число с максимальным временем выполнения O (диапазон)
Звучит неплохо, но я думаю, что это не так, потому что я отправляю случайные числа в базу данных и что все они на начальном этапе очень маловероятны. Итак, насколько это хорошо/плохо?
Я думаю, что это будет работать нормально, но я хочу это ЛУЧШЕ
А как насчет этого?
- найти случайное число
- запрашивает базу данных о том, сколько чисел занято в диапазоне всего диапазона, начиная с этого числа (этот первый шаг тривиален...)
- Если числа заняты в этом диапазоне, разделите диапазон на половину и повторите попытку. начиная с начального номера
- Если числа заняты, разделите диапазон наполовину и повторите попытку. начиная с начального номера
Если я правильно думаю, это даст число с максимальным временем O (log (range)).
Это довольно приятно, потому что log() довольно хорош. Однако я думаю, что этот метод часто будет настолько плохим, насколько это возможно. Потому что с нашими случайными числами мы, вероятно, всегда будем набирать числа в больших интервалах.
Итак, в начале наш чистый случайный метод, вероятно, лучше.
А как насчет наличия такого предела
- выберите текущее количество использованных номеров
- больше, чем X, подход с логарифмическим диапазоном
- если это не так, используйте чистый случайный метод
Что будет X и почему?
Итак, последний вопрос:
Это довольно легко и довольно сложно в то же время.
Я думаю, что это стандартная проблема, потому что много и много систем используют случайные идентификаторы (билеты на поддержку и т.д.), поэтому я не могу себе представить, что я первый, кто наткнулся на это.
Как бы вы решили это? Любой вход оценивается!
Есть ли maby существующий класс/процедура для этого, я могу использовать?
Или некоторые функции базы данных, которые я могу использовать?
Я хотел бы сделать это в PHP/Mysql
ВАЖНАЯ ИНФОРМАЦИЯ:
Я просто подумал о диапазоне/логарифмическом решении. Кажется, это полная фигня, извините за мою формулировку, потому что:
- что, если я нажму занятый номер при запуске?
Затем я разделяю свой диапазон так долго, если он равен только 1. И даже тогда число будет использовано.
Таким образом, он полностью совпадает с чистым случайным методом с самого начала, только хуже....
Я немного смущен. Я сделал это, но я оставлю его, потому что я считаю его хорошим примером сложнейшего мыслимого!