Bagaimana mungkin sequence.nextval menjadi nol di Oracle?

11

Saya memiliki urutan Oracle yang didefinisikan seperti ini:

CREATE SEQUENCE  "DALLAS"."X_SEQ"  
    MINVALUE 0 
    MAXVALUE 999999999999999999999999999 
    INCREMENT BY 1 START WITH 0 NOCACHE  NOORDER  NOCYCLE ;

Ini digunakan dalam prosedur tersimpan untuk memasukkan catatan:

PROCEDURE Insert_Record
                (p_name    IN  VARCHAR2,                
                 p_userid  IN  INTEGER,
                 cur_out   OUT TYPES_PKG.RefCursor)
    IS
        v_id NUMBER := 0;
    BEGIN
        -- Get id value from sequence
        SELECT x_seq.nextval
          INTO v_id
          FROM dual;

        -- Line below is X_PKG line 40
        INSERT INTO X
            (the_id,            
             name,                        
             update_userid)
          VALUES
            (v_id,
             p_name,                        
             p_userid);

        -- Return new id
        OPEN cur_out FOR
            SELECT v_id the_id
              FROM dual;
    END;

Kadang-kadang, prosedur ini mengembalikan kesalahan ketika dijalankan dari kode aplikasi.

ORA-01400: cannot insert NULL into ("DALLAS"."X"."THE_ID") 
ORA-06512: at "DALLAS.X_PKG", line 40 
ORA-06512: at line 1

Detail yang mungkin relevan atau tidak relevan:

  • Oracle Database 11g Edisi Perusahaan Rilis 11.2.0.1.0 - Produksi 64bit
  • Prosedur dieksekusi melalui Microsoft.Practices.EnterpriseLibrary - Data.Oracle.OracleDatabase.ExecuteReader (perintah DbCommand)
  • Aplikasi tidak membungkus panggilan dalam transaksi eksplisit.
  • Sisipan gagal sebentar-sebentar - kurang dari 1%

Dalam keadaan apa bisa x_seq.nextvalnol?

Corbin March
sumber
Berapa banyak kode di antara select & insert? Apakah ada BEGIN..END blokir atau pernyataan PENGECUALIAN dalam kode itu? Apakah v_id direferensikan sama sekali dalam kode itu? Agak aneh. Dapatkah Anda menempatkan blok "JIKA v_id IS NULL THEN .... END IF" langsung setelah pernyataan dan meninggalkan beberapa hasil debugging di suatu tempat jika urutannya ternyata menetapkan nol untuk v_id? Itu atau bungkus urutan pilih di blok BEGIN..ECECEPTION, karena mungkin ada sesuatu yang terjadi yang tidak tertangkap. Satu hal terakhir - apakah ada pemicu pada tabel yang Anda masukkan yang dapat menyebabkannya?
Philᵀᴹ
@ Phil - Pilihannya adalah tepat sebelum memasukkan. Tidak BEGIN, AKHIR, atau PENGECUALIAN selain dari proc MULAI / AKHIR. v_idhanya direferensikan dalam urutan pilih, masukkan, dan kursor akhir. Langkah kami selanjutnya adalah menambahkan kode debug. Kita mungkin harus menunggu hasil karena hanya terjadi dalam produksi dan sangat jarang. Ada pemicu yang menyisipkan ke dalam tabel audit. Saya sudah menyisirnya tanpa pistol merokok. Masalahnya juga kadang-kadang terjadi di tabel lain tanpa pemicu. Terima kasih telah melihatnya.
Corbin
5
Satu-satunya hal yang saya benar-benar dapat pikirkan saat ini adalah jika: new.the_id entah bagaimana akan menjadi NULL di pelatuk yang ada di tabel X.
Philᵀᴹ
@ Phil: ini pasti penyebab masalahnya. Anda harus menjawabnya.
René Nyffenegger
@ RenéNyffenegger-masalah juga terjadi pada procs yang memasukkan ke dalam tabel tanpa pemicu. Tampaknya bug peluang sama.
Corbin

Jawaban:

4

Saya cukup yakin ini pada akhirnya akan menjadi artefak dari kode Anda, atau driver .net yang Anda gunakan. Saya telah membuat demo cepat untuk Anda menggunakan SQL - PL / SQL murni dan tidak pernah mendapatkan nilai urutan yang hilang. Kebetulan kursor ref yang Anda gunakan mungkin tidak perlu dan kemungkinan berdampak pada kinerja dan keterbacaan kode - demo saya mencakup prosedur insert_record2 yang secara konsisten melakukan lebih dari 10% lebih cepat -dalam sekitar 26 detik di laptop saya vs 36 untuk versi kursor ref. Setidaknya menurut saya juga lebih mudah dimengerti. Anda jelas dapat menjalankan versi yang dimodifikasi terhadap basis data pengujian Anda lengkap dengan pemicu audit.

/* 
demo for dbse 
assumes a user with create table, create sequence, create procedure pivs and quota. 

*/

drop table dbse13142 purge;

create table dbse13142(
    the_id number not null
,   name   varchar2(20)
,   userid number)
;

drop sequence x_seq;
CREATE SEQUENCE  X_SEQ NOCACHE  NOORDER  NOCYCLE ;

create or replace PROCEDURE Insert_Record
                (p_name    IN  VARCHAR2,                
                 p_userid  IN  INTEGER,
                 cur_out   OUT sys_refcursor)
    IS
        v_id NUMBER := 0;
    BEGIN
        -- Get id value from sequence
        SELECT x_seq.nextval
          INTO v_id
          FROM dual;

        -- Line below is X_PKG line 40
        INSERT INTO dbse13142
            (the_id,            
             name,                        
             userid)
          VALUES
            (v_id,
             p_name,                        
             p_userid);

        -- Return new id
        OPEN cur_out FOR
            SELECT v_id the_id
              FROM dual;
    END;
/


create or replace PROCEDURE Insert_Record2
                (p_name    IN  VARCHAR2,                
                 p_userid  IN  INTEGER,
                 p_theid   OUT dbse13142.the_id%type)
    IS
    BEGIN
        -- Get id value from sequence
        SELECT x_seq.nextval
          INTO p_theid
          FROM dual;

        -- Line below is X_PKG line 40
        INSERT INTO dbse13142
            (the_id,            
             name,                        
             userid)
          VALUES
            (p_theid,
             p_name,                        
             p_userid);
    END;
/

set timing on

declare
   c sys_refcursor;
begin   
for i in 1..100000 loop
   insert_record('User '||i,i,c);
   close c;
end loop;
commit;
end;
/

select count(*) from dbse13142;
truncate table dbse13142;

declare
  x number;
begin   
for i in 1..100000 loop
   insert_record2('User '||i,i,x);
end loop;
commit;
end;
/

select count(*) from dbse13142;
truncate table dbse13142;
Niall Litchfield
sumber
1
dengan cara versi dengan pendekatan tradisional menggunakan pemicu untuk kolom the_id dan prosedur sebagai berikut juga berjalan lebih cepat membuat atau mengganti PROSEDUR Insert_Record3 (p_name IN dbse13142.name% type, p_userid IN dbse13142.userid% type, p_theid OUT dbse13142 .the_id% type) IS BEGIN INSERT INTO dbse13142 (nama, userid) VALUES (p_name, p_userid) mengembalikan the_id ke p_theid; AKHIR; /
Niall Litchfield
Setuju bahwa kemungkinan ada masalah dengan kode aplikasi atau driver. Saya hanya ingin tahu apa yang dapat menyebabkan null nextval sebagai efek samping. Membingungkan. Terima kasih atas tip kinerjanya. Ini saran bagus yang akan saya sarankan kepada tim.
Corbin
1
Corbin, maksud saya (dan Kevin) adalah bahwa ada sesuatu yang aneh terjadi di antara kode dan oracle Anda - jika Anda menjalankan tes murni dalam SQL Anda tidak mendapatkan efeknya. Tetapi lihat komentar Phil tentang pemicu audit (yang bisa Anda coba nonaktifkan).
Niall Litchfield
Saya mengerti poin yang dibuat. Masalahnya ada dalam procs memasukkan ke dalam tabel dengan dan tanpa pemicu sehingga pemicu tidak diperlukan. Ketika ada pemicu, itu hanya memasukkan ke dalam tabel audit. Saya sudah konfirmasi :new.the_idtidak tersentuh. Saya mengerti pertanyaan saya sangat sulit. Ini tahan terhadap google-fu saya dan beberapa orang menggaruk-garuk kepala di sini. Saya baru saja membayangkan seseorang mungkin mengenali gejala (dan perawatan) yang diberikan bola mata yang cukup. Terima kasih telah melihatnya.
Corbin
2

Coba lakukan test case. Buat tabel dummy dan masukkan 100.000 catatan menggunakan urutan Anda dari database. Saya yakin Anda tidak akan memiliki masalah. Selanjutnya coba masukkan hal yang sama dari aplikasi Anda.

Mungkinkah ini disebabkan oleh masalah lain seperti ketidakcocokan klien Oracle?

Solusi lain yang akan memperbaiki masalah tetapi tidak masalah adalah menambahkan pemicu di atas meja.
Sebelum Menyisipkan pada tabel di Dallas.X JIKA: the_id adalah null THEN SELECT x_seq.nextval INTO: the_id FROM dual; BERAKHIR JIKA;

kevinsky
sumber
Saya tidak dapat membuat kembali masalah secara lokal. Ini hanya terjadi dalam produksi dan jarang terjadi. Firasat saya adalah Anda benar tentang klien Oracle. Masalahnya muncul beberapa minggu yang lalu saat rilis di mana klien tidak diperbarui. Namun, rasanya ada sesuatu yang tidak cocok antara aplikasi dan db. Interaksi dari konsumen lain tampaknya bekerja dengan baik. Pemeriksaan nol bukan ide yang buruk, tetapi idealnya saya ingin membahas akar masalahnya dengan menyelesaikannya. Tapi siapa yang tahu? Work-around lebih baik daripada break.
Corbin
0

Saya belum memiliki priveldges untuk membuat komentar, jadi tulis ini sebagai jawaban: Karena Anda menggunakan versi Oracle> = 11.1, yang memungkinkan urutan dalam ekspresi PL / SQL alih-alih dalam SQL, coba ini:

   v_id := x_seq.nextval;

Alih-alih ini:

 -- Get id value from sequence
    SELECT x_seq.nextval
      INTO v_id
      FROM dual;

Atau, meskipun saya pernah mendengar keraguan / jebakan saat menggunakan ".currval", mungkin menghilangkan penugasan terpisah dari v_id dan hanya menggunakan kode ini ?:

 -- Line below is X_PKG line 40
        INSERT INTO X
            (the_id,            
             name,                        
             update_userid)
          VALUES
            (x_seq.nextval,
             p_name,                        
             p_userid);

        -- Return new id
        OPEN cur_out FOR
            SELECT x_seq.currval the_id
              FROM dual;

Maaf saya tidak punya instance 11g berguna sekarang untuk mencoba ini.

George3
sumber
jelas tidak ada bedanya. Saya menggunakan select into...11 sebanyak 9i dan 10g. Satu-satunya manfaat dari 11+ adalah dapat secara eksplisit merujuknya seperti yang Anda tunjukkan.
Ben