LINUX.ORG.RU

MySQL: получить младший свободный ID в прорежённой базе


0

2

Есть база с первичным ключём, что когда-то заполнялась по auto_increment, но сейчас стала сильно разрежённой (плотность заполнения около 20%). Есть мысли, как сделать выдачу новых ID потокобезопасной и не громоздкой?

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

Второй вариант — залочить, дёрнуть список всех ID и в цикле найти первый свободный чуть лучше, но тоже ужасен.

★★★★★

всё ужасно..
чего боишься-то? что номера кончатся?
закройся на техобслуживание, убери «дырки» в id любым из ужасных методов, не забыв переустановить autoincrement counter и всё. а код, который в продакшене работает - не трогай. пусть там дальше будет auto_increment
http://lists.mysql.com/mysql/198896

aol ★★★★★
()
Последнее исправление: aol (всего исправлений: 1)

Старые ID кончились чтоли ?

Сделай таблицу с временными ID, например 1-1000000,
удали из неё записи с ИД которые уже используются
для новых записей выдавай ИД из временной таблицы.

ilovewindows ★★★★★
()

Если бы это был не sql, а какой-нибудь массив структур, то нужно было бы вести список свободных ячеек: когда ячейка освобождается, кладём ее номер в список; когда хотим получить свободную ячейку, изымаем ее номер из списка.

Manhunt ★★★★★
()
Ответ на: комментарий от aol

чего боишься-то? что номера кончатся?

Нет. Банальное повторное использование «коротких» ID пользователей :)

закройся на техобслуживание, убери «дырки» в id любым из ужасных методов

Сдвигать имеющиеcя ID нельзя — они в нереляционной форме в ряде мест задействованы.

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от Manhunt

Если бы это был не sql, а какой-нибудь массив структур

На Java, когда все ID были в памяти и при залочке потока я эту задачу решал несколькими достаточно эффективными способами когда-то. Но тут — работающая SQL-база :-/

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от aol

этопрекрааасно ;)

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

KRoN73 ★★★★★
() автор топика

сделай поле id 64-битным, и пусть хоть там хоть какое распределение дырок будет, на сто лет ещё хватит.

thesame ★★★★
()

А нельзя сделать 64-битные id? Это решило бы проблему, так как исчерпать их до второго пришествия ты всё равно не успеешь.

Manhunt ★★★★★
()
Ответ на: комментарий от Manhunt

Иерархические запросы позволяют вычленить отсутствующие элементы. Но на работающей базе с большим количеством строк такое может не взлететь просто потому, что памяти не хватит. =)

winlook38 ★★
()
Ответ на: комментарий от ilovewindows

Тогда уж лучше сразу делать таблицу из свободных ID (таблицу «дырок») до последней и выдавать из нее? Как только все выбрали - возвращаемся к автоинкременту. Или еще одну итерацию (к тому времени же дырки опять появятся)

Deleted
()
Ответ на: комментарий от KRoN73

Сдвигать имеющиеcя ID нельзя — они в нереляционной форме в ряде мест задействованы.

Т.е. id может не быть в базе, но где то используется? Тогда повторное использование id вызовет некоторые проблемы.

at ★★
()
Ответ на: комментарий от Deleted

Можно и сразу из «дырок», но тогда каждую проверять. Проще сгенерить
скриптом , потом одним запросом удалить уже используемые. Можно по частям добавлять, чтобы сильно и надолго базу не грузить. Базу можно не блокировать, все равно новые с «большими» номерами идут, а дырки из младших номеров формируются. Остаётся только в клиенте или в базе алгоритм генерации нового ИД поправить. Но вообще изврат :).

ilovewindows ★★★★★
()
Ответ на: комментарий от sjinks

Так просто =) И, похоже, это то, что нужно ТС. Только еще min() добавить.

winlook38 ★★
()
Ответ на: комментарий от KRoN73

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

все равно же как-то не изящно... ну кроме поисковиков.

dk-
()
Ответ на: комментарий от Deleted

Тогда уж лучше сразу делать таблицу из свободных ID

О! А это, в принципе, вариант.

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от at

Т.е. id может не быть в базе, но где то используется?

Нет. id удалялись только для объектов, не оставивших нигде следов (обычно это так и не активировавшиеся спамботы, пользователи, так и не начавшие писать и т.п.)

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от dk-

все равно же как-то не изящно

Есть альтернативы? :) username — не лучший вариант, так как в теории может меняться. Плюс возникает проблема «минификации» длинных имён, содержащих русский, пробелы и т.п.

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от KRoN73

У метода есть минус. Никогда не вернет id=1, если его нет. Но в этой задаче это наверное несущественно

anonymous
()

Склепай собственный sequence на базе redis.

power
()
Ответ на: комментарий от KRoN73

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

ilovewindows ★★★★★
()
Ответ на: комментарий от ilovewindows

На 56М записях работало минуту. Не то, чтобы в туалет и чайку, но ТС тоже не устроит. А вот на таблицах с 1-1,5М записей работает от 2 до 6 секунд, что может быть вполне приемлемым, если операция редкая. Но тут еще нужно учитывать СУБД и ее настройки, я думаю (тестировал на Oracle 9i с реальными данными).

winlook38 ★★
()
Ответ на: комментарий от winlook38

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

ilovewindows ★★★★★
()
Ответ на: комментарий от winlook38

А вот на таблицах с 1-1,5М записей работает от 2 до 6 секунд, что может быть вполне приемлемым, если операция редкая

Я выше писал, что речь о базе пользователей. 15 тыс записей — мелочь. И новые записи редко идут.

А там, где миллионы записей, там id обычно итак плотно идут :)

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от KRoN73

Я выше писал, что речь о базе пользователей. 15 тыс записей — мелочь. И новые записи редко идут.

А зачем, собственно, всё это надо было делать? ID двухбайтовый что ли? 4-байтовый переполниться не мог.

Legioner ★★★★★
()
Ответ на: комментарий от Legioner

А зачем, собственно, всё это надо было делать?

MySQL: получить младший свободный ID в прорежённой базе (комментарий)

Ну не нравится мне чисто эстетически, когда в базе 15 тыс записей, а ID юзеров по 85 тыс. идут :)

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от KRoN73

На таких данных мгновенно отрабатывает. Я просто тестировал, как сказал ilovewindows на больших данных.

winlook38 ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.