|
ru.cgi.perl- RU.CGI.PERL ------------------------------------------------------------------ From : Andrey Sapozhnikov 2:5020/400 27 Aug 2004 18:16:30 To : Artem Chuprina Subject : Re: Программируем MySQL под CGI Perl --------------------------------------------------------------------------------
Artem Chuprina пишет:
> Igor Sigaev -> Serge Chervjakov @ Wed, 25 Aug 2004 20:50:02 +0000 (UTC):
>
> IS> А если пользователей будет больше? А, самое главное, если будут "гонять"
> IS> данные чаще ? ...
>
> Вообще на подобные задачи обычно применяется другой метод. Поле,
> естественно, делается не автоинкрементным, а просто числовым. Таблица
> блокируется, выбирается случайное число, проверяется, есть ли оно в
> базе. Если есть - выбирается следующее случайное число, и т.д. Если
> нет - используется это. Запись вставляется, таблица разблокируется.
> Разумно выбор случайного числа ограничить пятком итераций - если все
> пять уже есть в базе, то либо база слишком набита (почти под завязку
> диапазона чисел), либо генератор случайных чисел очень плохой (например,
> стандартный от солярки - всего 15 бит), и тут лучше отвалить операцию,
> чем зациклить сервер.
Просто при проектировании БД надо тоже включать алгоритмическое мышление :)
Hам нужно найти не запись, а "дырку" между записями. Можно изначально не
удалять записи, а помечать их как освободившиеся. Hо это накладно если
таковых записей очень много. Можно пользоваться генератором случайных чисел,
но раз в год и палка стреляет и генератор в почти пустой базе пять раз
попадает в очко. Можно и ключ сделать очень длинный и не повторяющийся
и инкрементировать его до следующего цикла расширения нашей вселенной...
Тоже некузяво :) Hо почему бы не добавить к записи N флажок
указывающий на то, что запись N+1 свободна? Тогда поиск дырки сведется к:
1. SELECT 1 FROM tbl WHERE id = 1 ?
Если записи 1 нет - вставляем запись N = 1, если есть - переходим к п. 2
2. SELECT id FROM tbl WHERE nextisfree = TRUE ORDER BY id LIMIT 1
Переходим к вставке записи N = id + 1
Для PostgreSQL:
SELECT CASE
WHEN NOT EXISTS (SELECT 1 FROM tbl WHERE id = 1) THEN
1
ELSE
(SELECT id FROM tbl WHERE nextisfree = TRUE ORDER BY id LIMIT 1) + 1
END;
Вставка записи N:
1. Проверяем есть ли запись N + 1
Если есть - INSERT INTO tbl(id, nextisfree) VALUES(N, FALSE)
иначе INSERT INTO tbl(id, nextisfree) VALUES(N, TRUE)
2. Снимаем флажок nextisfree с записи N - 1
UPDATE tbl SET nextisfree = FALSE WHERE id = N - 1
Для PostgreSQL:
INSERT INTO tbl(id, nextisfree) VALUES (:N,
NOT EXISTS(SELECT 1 FROM tbl WHERE id = :N + 1));
UPDATE tbl SET nextisfree = FALSE WHERE id = :N - 1;
Все поиски исключительно быстрые при правильно созданных
индексах. Потери памяти - 1 бит на запись (теоретически :))
--
Андрей
--- ifmail v.2.15dev5.3
* Origin: Demos online service (2:5020/400)
Вернуться к списку тем, сортированных по:
Архивное /ru.cgi.perl/6577ab30d542.html, оценка из 5, голосов 10
|