3

複数のレコードを1つのテーブルに挿入するマルチスレッドプロセスがあります。挿入はストアドプロシージャで実行され、シーケンスINTOは変数として生成され、その変数は後で。内で使用されますINSERT

mysequence.nextval私がそれ自体の内部で行っていないことをINSERT考えると、2つの並行プロセスが1つの順序でシーケンスを取得し、次に逆の順序で挿入を行うことが可能であると思います。この場合、シーケンス番号は実際の挿入順序を反映しません。

また、各挿入sysdateDATE列にを記録しますが、2つのレコードの日付が一致することがよくあり、タイを解除するにはシーケンス番号で並べ替える必要があることに気付きました。しかし、前の問題を考えると、これは実際の挿入順序を保証するものではないようです。

データベースへの挿入の絶対順序をどのように決定できますか?

4

7 に答える 7

5

DATEデータ型は秒のみになりますが、TIMESTAMPはミリ秒になります。それで問題は解決しますか?

Oracleのドキュメントによると:

TIMESTAMP:日付の年、月、日の値、および時間の時間、分、秒の値。ここで、fractional_seconds_precisionは、SECOND日時フィールドの小数部分の桁数です。受け入れられるfractional_seconds_precisionの値は0〜9です。デフォルトは6です。デフォルトの形式は、NLS_DATE_FORMATパラメーターによって明示的に決定されるか、NLS_TERRITORYパラメーターによって暗黙的に決定されます。サイズは、精度に応じて7〜11バイトです。このデータ型には、日時フィールドYEAR、MONTH、DAY、HOUR、MINUTE、およびSECONDが含まれます。小数秒が含まれていますが、タイムゾーンはありません。

一方date、そうではありません:

日付:有効な日付範囲は、紀元前4712年1月1日から西暦9999年12月31日までです。デフォルトの形式は、NLS_DATE_FORMATパラメーターによって明示的に決定されるか、NLS_TERRITORYパラメーターによって暗黙的に決定されます。サイズは7バイトに固定されています。このデータ型には、日時フィールドYEAR、MONTH、DAY、HOUR、MINUTE、およびSECONDが含まれます。分数秒やタイムゾーンはありません。

もちろん、そうは言っても、レコードが書かれたときになぜそれが重要なのかはわかりませんが、それはあなたの問題を解決するかもしれない方法です。

于 2010-07-16T15:19:43.553 に答える
2

シーケンスはスレッドセーフである必要があります。

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 "2人のユーザーが同じシーケンスに同時にアクセスしている場合、シーケンス番号はそれぞれシーケンス番号は他のユーザーによっても生成されているため、ユーザーが受け取るにはギャップがある可能性があります。」数値は1、2、3、4、5ではない可能性があります(私の例のように->これを恐れる場合はキャッシュを増やすことができます)

http://forums.oracle.com/forums/thread.jspa?threadID=910428 "トランザクションをコミットするかロールバックするかに関係なく 、シーケンスは即座に永続的にインクリメントされます。シーケンスでNextValに同時にアクセスすると、常に各呼び出し元に個別の値が返されます。」

挿入が故障し、シーケンス値が必要な場合は、returning句を使用してください。

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

それからあなたはそれがその場で挿入されたことを知っています。

于 2010-07-16T16:26:15.067 に答える
0

いくつかの効果が起こっています。今日のコンピューターは、タイマーが追いつかないほど多くの操作を1秒あたりに実行できます。また、現在の時刻を取得するのはややコストのかかる操作であるため、値が変更されるまで数ミリ秒続く可能性のあるギャップがあります。そのsysdateため、さまざまな行で同じ結果が得られます。

次に、挿入の問題を解決します。シーケンスを呼び出すnextvalと、この値がシーケンスから削除されることが保証されます。2つのスレッドが複数回呼び出す場合nextval、インターリーブされた番号を取得できます(つまり、スレッド1は1 3 4 7を参照し、スレッド2は2 5 6 8を参照します)が、各スレッドが異なる番号を取得することを確認できます。

したがって、の結果をすぐに使用しなくても、nextval安全である必要があります。データベース内の「絶対」挿入順序については、これを判断するのは難しいかもしれません。たとえば、DBは、行をディスクに書き込む前にキャッシュに保持することができます。ディスクアクセスを最適化するために、行を並べ替えることができます。ただし、結果を挿入した順序で行に割り当てる限りnextval、これは問題ではなく、常に順番に挿入されているように見えるはずです。

于 2010-07-16T15:22:26.620 に答える
0

データベースへの挿入順序の概念はあるかもしれませんが、検索順序の概念は確かにありません。データベースから返される行は、DBがそれらを返すのに適していると判断した順序で返されます。これは、データベースに挿入された順序とは関係がない場合もあります。また、行がDBに挿入される順序は、行がディスクに物理的に格納される方法とはほとんど関係がない場合があります。

ORDER BY句を使用せずに、DBクエリからの注文に依存するのは愚かです。順序を確認したい場合は、挿入するレコードを作成するときに、ロジック内でその関係を正式なレベル(シーケンス、タイムスタンプなど)で維持する必要があります。

于 2010-07-16T15:25:24.853 に答える
0

トランザクションが分離している場合は、テーブルのora_rowscn疑似列からこれを判別できます。

[編集]もう少し詳しく説明します。これが役に立たない場合は、回答を削除します。デフォルト以外の「rowdependencies」句を使用してテーブルを作成しない限り、scnでタグ付けされたブロックの他の行があります。したがって、これは誤解を招く可能性があります。アプリケーションを変更せずにこの情報が本当に必要な場合は、この句を使用してテーブルを再構築する必要があります。

于 2010-07-16T15:35:09.137 に答える
0

あなたが解決しようとしている問題についてのあなたの説明を考えると、私はシーケンスがうまくいくと思います。同じストアドプロシージャを呼び出す2つのプロセスがあり、2番目の(時系列の)プロセスが何らかの理由で最初に終了する場合、それは実際に関連していますか?プロシージャが呼び出された順序(RACを使用している場合を除く)は、データベースに書き込まれた順序よりも意味があると思います。

行が挿入された順序が本当に心配な場合は、insertsステートメントが発行されたときではなく、コミットが発行されたときを確認する必要があります。それ以外の場合は、可能性として次のシナリオがあります。

  1. トランザクション1が開始されます
  2. トランザクション2が開始されます
  3. トランザクション3が開始されます
  4. トランザクション2の挿入
  5. トランザクション1は挿入します
  6. トランザクション3の挿入
  7. トランザクション3のコミット
  8. トランザクション1のコミット
  9. トランザクション2のコミット

この場合、トランザクション1が最初に開始され、トランザクション2が最初に挿入され、トランザクション3が最初にコミットされます。シーケンス番号から、トランザクションが開始された順序がわかります。タイムスタンプフィールドは、挿入がいつ発行されたかを示します。コミットの順序を取得する唯一の信頼できる方法は、テーブルへの書き込みをシリアル化することです。これは一般的に悪い考えです(スケーラビリティが失われます)。

于 2010-07-16T16:32:43.633 に答える
0

(a)各レコードにタイムスタンプを追加し、(b)シーケンスNEXTVALをINSERTステートメントに移動する必要があります。

そうすれば、テーブルをクエリするときにORDER BY timestamp, id、行が実際に挿入された順序になります。

于 2010-07-19T06:01:09.520 に答える