Как определить фактический порядок вставки строк в базу данных? - PullRequest
3 голосов
/ 16 июля 2010

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

Учитывая, что я не делаю mysequence.nextval внутри самого INSERT, это заставляет меня думать, что два параллельных процесса могут получить последовательность в одном порядке, а затем выполнить вставки в обратном порядке. Если это так, то порядковые номера не будут отражать истинный порядок вставки.

Я также записываю sysdate в столбце DATE для каждой из моих вставок, но я заметил, что часто совпадают даты для двух записей, и мне нужно отсортировать по порядковому номеру, чтобы разорвать связь. Но, учитывая предыдущую проблему, это не гарантирует фактического порядка вставки.

Как определить абсолютный порядок вставки в базу данных?

Ответы [ 7 ]

5 голосов
/ 16 июля 2010

DATE типы данных идут только в секундах, а TIMESTAMP - в миллисекундах.Решит ли это проблему?

Согласно документации Oracle:

TIMESTAMP: значения даты в году, месяце и дне, а также значения времени в часах, минутах и ​​секундах.где fraal_seconds_precision - количество цифр в дробной части поля ВРЕМЯ datetime.Допустимые значения fraal_seconds_precision - от 0 до 9. Значение по умолчанию - 6. Формат по умолчанию определяется явно параметром NLS_DATE_FORMAT или неявно параметром NLS_TERRITORY.Размеры варьируются от 7 до 11 байт, в зависимости от точности.Этот тип данных содержит поля даты и времени YEAR, MONTH, DAY, HOUR, MINUTE и SECOND.Он содержит доли секунды, но не имеет часового пояса.

Принимая во внимание, что date не:

ДАТА: Действительный диапазон дат с 1 января 4712 г. до н.э. до декабря31, 9999 г. н.э.Формат по умолчанию определяется явно параметром NLS_DATE_FORMAT или неявно параметром NLS_TERRITORY.Размер фиксируется в 7 байтов.Этот тип данных содержит поля даты и времени YEAR, MONTH, DAY, HOUR, MINUTE и SECOND.У него нет дробных секунд или часового пояса.

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

2 голосов
/ 16 июля 2010

Последовательность должна быть поточно-ориентированной:

create table ORDERTEST (
    ORDERID number not null ,
    COLA   varchar2(10) ,
    INSERTDATE date default sysdate,
    constraint ORDERTEST_pk primary key (orderid)
) ;

create sequence ORDERTEST_seq start with 1 nocycle nocache ;

insert into ORDERTEST (ORDERID, COLA, INSERTDATE)
                select ORDERTEST_SEQ.NEXTVAL , substr(OBJECT_NAME,1,10), sysdate 
                  from USER_OBJECTS 
                 where rownum <= 5; --just to limit results

select * 
  from ORDERTEST
 order by ORDERID desc ;

 ORDERID                COLA       INSERTDATE                
---------------------- ---------- ------------------------- 
5                      C_COBJ#    16-JUL-10 12.15.36        
4                      UNDO$      16-JUL-10 12.15.36        
3                      CON$       16-JUL-10 12.15.36        
2                      I_USER1    16-JUL-10 12.15.36        
1                      ICOL$      16-JUL-10 12.15.36  

теперь в другом сеансе:

insert into ORDERTEST (ORDERID, COLA, INSERTDATE)
            select ORDERTEST_SEQ.NEXTVAL , substr(OBJECT_NAME,1,10), sysdate 
              from USER_OBJECTS 
             where rownum <= 5; --just to limit results

select * 
  from ORDERTEST
 order by ORDERID desc ;

 5 rows inserted
ORDERID                COLA       INSERTDATE                
---------------------- ---------- ------------------------- 
10                     C_COBJ#    16-JUL-10 12.17.23        
9                      UNDO$      16-JUL-10 12.17.23        
8                      CON$       16-JUL-10 12.17.23        
7                      I_USER1    16-JUL-10 12.17.23        
6                      ICOL$      16-JUL-10 12.17.23     

Последовательность Oralce является поточно-ориентированной: http://download.oracle.com/docs/cd/B19306_01/server.102/b14231/views.htm#ADMIN020 "Если два пользователяобращаются к одной и той же последовательности одновременно, тогда порядковые номера, которые получает каждый пользователь, могут иметь пропуски, потому что порядковые номера также генерируются другим пользователем ".числа не могут быть 1,2,3,4,5 (как в моем примере -> если вы боитесь этого, вы можете увеличить кэш)

это также может помочь, хотя они не размещают свой источник: http://forums.oracle.com/forums/thread.jspa?threadID=910428 "последовательность увеличивается на единицу сразу и навсегда, независимо от того, фиксируете ли вы транзакцию или откатывает ее. Параллельный доступ к NextVal последовательности всегда будет возвращать отдельные значения каждому вызывающему."

Если вашбоюсь, вставки будут не в порядке, и вам нужно, чтобы значение последовательности использовало возвращаемое предложение:

declare 
x number ;
begin 
insert into ORDERTEST (ORDERID, COLA, INSERTDATE)
                values( ORDERTEST_SEQ.NEXTVAL , 'abcd', sysdate)
                returning orderid into x;

dbms_output.put_line(x);
end;

--11

тогда вы знаете, что оно вставлено прямо тогда и там.

0 голосов
/ 19 июля 2010

Вы должны (а) добавить метку времени к каждой записи и (б) переместить последовательность NEXTVAL в оператор INSERT.

Таким образом, когда вы запрашиваете таблицу, вы можете ORDER BY timestamp, id,фактически будет порядок, в котором строки были фактически вставлены.

0 голосов
/ 16 июля 2010

Учитывая ваше описание проблемы, которую вы пытаетесь решить, я думаю, что последовательности будут в порядке. Если у вас есть два процесса, которые вызывают одну и ту же хранимую процедуру, а второй (хронологический) завершает первый по какой-то причине, действительно ли это актуально? Я думаю, что порядок, в котором были вызваны процедуры (которые будут отражены в последовательности (если вы не используете RAC)), будет более значимым, чем порядок, в котором они были записаны в базу данных.

Если вы действительно беспокоитесь о последовательности, в которую были вставлены строки, вам нужно посмотреть, когда были выполнены коммиты, а не когда были вставлены операторы insert. В противном случае возможен следующий сценарий:

  1. Транзакция 1 запущена
  2. Транзакция 2 запущена
  3. Транзакция 3 запущена
  4. Транзакция 2 вставки
  5. Транзакция 1 вставляет
  6. Транзакция 3 вставки
  7. Транзакция 3 фиксирует
  8. Транзакция 1 фиксирует
  9. Транзакция 2 фиксирует

В этом случае транзакция 1 была запущена первой, транзакция 2 вставлена ​​первой, а транзакция 3 зафиксирована первой. Порядковый номер дает вам хорошее представление о порядке, в котором были начаты транзакции. Поле метки времени даст вам представление о том, когда были выпущены вставки. Единственный надежный способ получить заказ на коммиты - это сериализация записей в таблицу, что, как правило, является плохой идеей (она устраняет масштабируемость).

0 голосов
/ 16 июля 2010

Если транзакции являются отдельными, это можно определить по псевдостолбцу ora_rowscn для таблицы.

[Изменить] Немного подробнее, и я удалю свой ответ, если он не будет полезен - если вы не создали таблицу с предложением не по умолчанию "rowdependencies", у вас будут другие строки из блока, помеченного с помощью scn, так что вводить в заблуждение Если вы действительно хотите получить эту информацию без изменения приложения, вам придется перестроить таблицу с помощью этого пункта.

0 голосов
/ 16 июля 2010

Хотя может существовать некоторая концепция порядка вставки в базу данных, определенно нет концепции порядка поиска.Любые строки, которые возвращаются из базы данных, будут возвращаться в любом порядке, в котором БД сочтет нужным их вернуть, и это может иметь или не иметь НИЧЕГО общего с порядком, в котором они были вставлены в базу данных.Кроме того, порядок, в котором строки вставляются в БД, может практически не иметь отношения к тому, как они физически хранятся на диске.

Полагаться на любой порядок из запроса к БД без использования предложения ORDER BYглупость.Если вы хотите быть уверены в каком-либо порядке, вам необходимо поддерживать эти отношения на формальном уровне (последовательности, временные метки и т. Д.) В своей логике при создании записей для вставки.

0 голосов
/ 16 июля 2010

Происходит несколько эффектов. Сегодняшние компьютеры могут выполнять столько операций в секунду, что таймеры не успевают. Кроме того, получение текущего времени является довольно дорогой операцией, поэтому у вас есть промежутки, которые могут длиться несколько миллисекунд, пока значение не изменится. Вот почему вы получаете одинаковые sysdate для разных строк.

Теперь, чтобы решить вашу проблему вставки. Вызов nextval для последовательности гарантированно удалит это значение из последовательности. Если два потока вызывают nextval несколько раз, вы можете получить чередующиеся числа (т.е. поток 1 увидит 1 3 4 7, а поток 2 увидит 2 5 6 8), но вы можете быть уверены, что каждый поток получит разные номера.

Так что, даже если вы не используете результат nextval сразу, вы должны быть в безопасности. Что касается «абсолютного» порядка вставки в базу данных, это может быть трудно сказать. Например, БД может хранить строки в кэше перед записью их на диск. Строки могут быть переупорядочены для оптимизации доступа к диску. Но до тех пор, пока вы присваиваете результаты из nextval своим строкам в том порядке, в котором вы их вставляете, это не должно иметь значения, и они всегда должны казаться вставленными по порядку.

...