Гарантирование того, что значения полей являются непрерывной последовательностью - PullRequest
1 голос
/ 07 ноября 2011

У меня есть такая таблица

mysql> describe obj;
+----------+----------+------+-----+---------+----------------+
| Field    | Type     | Null | Key | Default | Extra          |
+----------+----------+------+-----+---------+----------------+
| id       | int(11)  | NO   | PRI | NULL    | auto_increment |
| data     | blob     | YES  |     | NULL    |                |
| sequence | int(11)  | YES  | UNI | NULL    |                |
| created  | datetime | YES  |     | NULL    |                |
+----------+----------+------+-----+---------+----------------+

Я хочу, чтобы значения в поле sequence были непрерывной последовательностью, то есть без пропуска и переключения, и основаны на отметке времени created. В настоящее время я получаю это на уровне приложения. После каждой вставки:

while (true)
   lastSequence = max(sequence)
   if (update obj with lastSequence + 1)
      break

Таким образом, он не может пропустить, но нет гарантии, что ордер sequence совпадает с ордером created. С другой стороны, я мог бы упорядочить по created в подзапросе, но в среде cuncurrent могут происходить странные вещи, пока подзапрос выполняется, если я не сериализую все записи, но я думаю, что это убьет производительность. Есть идеи на эту тему?

Ответы [ 2 ]

2 голосов
/ 07 ноября 2011

Там нет волшебной пули.

Автоинкрементные номера идентификаторов не будут работать, потому что при откате транзакции вы получите пробел.

Код приложения вне транзакции не будет работать, поскольку он не может гарантировать, чтопорядок «последовательности» будет соответствовать порядку «создан».

Выполнение всей работы в рамках одной сериализуемой транзакции будет работать, но определенно повлияет на производительность.Влияет ли это на производительность так сильно, что его нельзя использовать - вопрос открытый;проверить и измерить.

Так что-то вроде этого (PostgreSQL) должно работать, но может быть недостаточно быстрым.(Возьмем приведенное ниже время с небольшим количеством соли. Никаких одновременных пользователей, небольшие таблицы.)

set transaction isolation level serializable;
begin;

insert into obj (sequence, time_created)
select min(n), current_timestamp 
from serial_integers where time_stamp is null;
-- 0.125ms

update serial_integers
set time_stamp = current_timestamp
where n = (select min(n)
from serial_integers where time_stamp is null);
-- 0.161ms

commit;
-- 15ms

На практике я бы протестировал оборачивание этого в функцию (хранимую процедуру), частично для устраненияподзапрос в операторе UPDATE.

1 голос
/ 07 ноября 2011

В MySQL вы используете auto_increment точно так же, как вы используете в поле ID.

В Oracle вы бы использовали секвенсор.

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

Пробелы произойдут , если вы удалите записи. Если вы хотите использовать значения даты / времени, вы должны перейти на уровень ниже миллисекунды, поскольку базы данных очень быстрые. Oracle использует systimestamp и передает секунды как минимум в 6 мест.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...