Oracle'da array.nextval nasıl boş olabilir?


11

Böyle tanımlanmış bir Oracle dizisi var:

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

Kayıtlı bir yordamda kayıt eklemek için kullanılır:

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;

Bazen bu yordam, uygulama kodundan yürütüldüğünde bir hata döndürür.

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

Alakalı olabilecek veya olmayabilecek ayrıntılar:

  • Oracle Database 11g Enterprise Edition Sürüm 11.2.0.1.0 - 64bit Üretim
  • Yordam Microsoft.Practices.EnterpriseLibrary - Data.Oracle.OracleDatabase.ExecuteReader (DbCommand komutu) aracılığıyla yürütülür.
  • Uygulama, çağrıyı açık bir işlemde sarmaz.
  • Ek parça aralıklı olarak başarısız -% 1'den az

Hangi şartlar altında x_seq.nextvalboş olabilir ?


Seç ve ekle arasında ne kadar kod var? Bu kodda herhangi bir BEGIN..END bloğu veya herhangi bir EXCEPTION deyimi var mı? Bu kodda v_id referansı var mı? Biraz garip görünüyor. Doğrudan deyimden sonra bir "IF v_id IS NULL THEN .... END IF" bloğu koyabilir ve dizi aslında v_id için null atarsa ​​bir yerde hata ayıklama çıktısı bırakabilir misiniz? Bu veya dizi seçimini bir BEGIN..EXCEPTION bloğuna sarın, çünkü yakalanmayan bir şey olabilir. Son bir şey - içine yerleştirdiğiniz masaya neden olabilecek bir tetikleyici var mı?
Philᵀᴹ

@Phil - Seçim, eklemeden hemen önce. Proc BEGIN / END dışında BEGIN, END veya EXCEPTION yok. v_idyalnızca dizi seçimi, ekleme ve son imleçte belirtilir. Bir sonraki adımımız hata ayıklama kodunu eklemekti. Sadece üretimde ve çok seyrek olduğu için sonuçları beklemek zorunda kalabiliriz. Bir denetim tablosuna eklenen bir tetikleyici vardır. Sigara silahı olmadan taradım. Sorun, zaman zaman tetikleyici olmayan diğer tablolarda da oluşur. Baktığınız için teşekkürler.
Corbin Mart

5
Şu anda gerçekten düşünebileceğim tek şey şuysa: new.the_id, tablo X'deki tetikleyicide bir şekilde NULL olur.
Philᵀᴹ

@Phil: Bu kesinlikle sorunun nedeni. Cevap vermelisin.
René Nyffenegger

@ RenéNyffenegger -sorunsuz tablolara eklemek procs da sorun oluşur. Eşit bir fırsat hatası gibi görünüyor.
Corbin Mart

Yanıtlar:


4

Bu, kodunuzun veya kullandığınız .net sürücüsünün bir parçası olacağından eminim. Ben saf SQL - PL / SQL kullanarak hızlı bir demo çaldı ve asla kayıp dizi değeri elde. Bu arada kullandığınız ref imleci muhtemelen gereksizdir ve muhtemelen kodun performansını ve okunabilirliğini etkiler - demo'm, dizüstü bilgisayarımda sürekli olarak% 10'un üzerinde daha hızlı performans gösteren bir insert_record2 prosedürü içeriyor - ref imleç sürümü için 36. En azından anlaşılması daha kolay olduğunu düşünüyorum. Açıkça değiştirilmiş bir sürümü, denetim tetikleyicisiyle tamamlanan test veritabanınıza karşı çalıştırabilirsiniz.

/* 
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;

1
bu arada the_id sütunu için tetikleyici ve geleneksel olarak aşağıdaki prosedürü kullanan bir sürüm de daha hızlı bir şekilde oluşturuldu veya değiştirildi PROCEDURE Insert_Record3 (p_name IN dbse13142.name% türü, p_userid IN dbse13142.userid% türü, p_theid OUT dbse13142 .the_id% type) dbse13142 (ad, kullanıcı kimliği) DEĞERLERİNİ (p_name, p_userid) BAŞLATIR; the_id değerini p_theid'e döndürür; SON; /
Niall Litchfield

Bunun muhtemelen uygulama kodu veya sürücü ile ilgili bir sorun olduğunu kabul etti. Sadece bir yan etki olarak null bir sonraki değere neyin neden olabileceğini merak ediyorum. Şaşırtıcı. Performans ipucu için teşekkürler. Takıma önereceğim iyi bir tavsiye.
Corbin Mart

1
Corbin, demek istediğim (ve Kevin), kodunuz ve kehanetiniz arasında garip bir şey oluyor - eğer testi tamamen SQL'de çalıştırırsanız, etkiyi alamazsınız. Ancak Phil'in denetim tetikleyicisi hakkındaki yorumuna bakın (devre dışı bırakmayı deneyebilirsiniz).
Niall Litchfield

Verilen noktaları anlıyorum. Sorun, tetikleyicili veya tetikleyicisiz tablolara eklenen proc'larda bulunur, bu nedenle tetikleyici gerekmez. Bir tetikleyici mevcut olduğunda, basitçe bir denetim tablosuna eklenir. Ben :new.the_idel değmemiş olduğunu doğruladım . Sorumun uzun bir atış olduğunu anlıyorum. Benim google-fu'ya dayanıklı ve birkaç kişi burada kafalarını kaşıyor. Birisinin yeterince göz küresi verilen belirtiyi (ve tedaviyi) tanıyabileceğini düşündüm. Baktığınız için teşekkürler.
Corbin Mart

2

Test senaryosu yapmayı deneyin. Sahte bir tablo oluşturun ve veritabanınızdaki sıranızı kullanarak 100.000 kayıt ekleyin. Bahse girerim ki hiç problem yaşamayacaksın. Sonra aynı şeyi uygulamanızdan eklemeyi deneyin.

Bunun nedeni Oracle istemci uyumsuzluğu gibi diğer sorunlardan kaynaklanıyor olabilir mi?

Sorunu çözecek ancak sorunu çözmeyecek bir başka çözüm de tabloya bir tetikleyici eklemektir.
Dallas.X üzerinde tabloya yerleştirmeden önce EĞER: the_id null boş THEN SELECT x_seq.nextval INTO: the_id FROM dual; END IF;


Sorunu yerel olarak yeniden oluşturamıyorum. Sadece üretimde olur ve orada nadiren olur. Benim önsezim Oracle istemcisi hakkında doğru olduğunuzu. Sorun istemci bir yayın sırasında birkaç hafta önce ortaya değil güncellendi. Ancak, bir şey app ve db arasında anlaşamıyor gibi geliyor. Diğer tüketicilerden gelen etkileşimler iyi çalışıyor gibi görünüyor. Sıfır kontrolü kötü bir fikir değil, ama ideal olarak, sorunun etrafındaki işe karşı çözümüne ulaşmak istiyorum. Gerçi kim bilir? Bir çözüm, kırılmaktan daha iyidir.
Corbin Mart

0

Henüz yorum yapmak için priveldges yok, bu yüzden bu bir cevap olarak yazma: SQL yerine PL / SQL ifadelerinde diziler sağlayan Oracle sürümü> = 11.1 kullandığınız için, şunu deneyin:

   v_id := x_seq.nextval;

Bunun yerine:

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

Ya da, ".currval" kullanırken şüpheler / tuzaklar duymama rağmen, v_id'in ayrı atamasını atlayabilir ve sadece bu kodu kullanabilir miyim ?:

 -- 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;

Üzgünüm, şimdi denemek için kullanışlı bir 11g örneğim yok.


kesinlikle hiç fark etmez. Kullandığım select into...9i ve 10g olduğunca 11'de. 11 + 'nın tek yararı, işaret ettiğiniz gibi açıkça referans verebilmektir.
Ben
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.