sequence.nextval เป็นอย่างไรใน Oracle


11

ฉันมีลำดับ Oracle ที่กำหนดดังนี้:

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

มันถูกใช้ในขั้นตอนการจัดเก็บเพื่อแทรกบันทึก:

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;

บางครั้งโพรซีเดอร์นี้ส่งคืนข้อผิดพลาดเมื่อเรียกใช้งานจากโค้ดแอ็พพลิเคชัน

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

รายละเอียดที่อาจเกี่ยวข้องหรือไม่เกี่ยวข้อง:

  • Oracle Database 11g Enterprise Edition รีลีส 11.2.0.1.0 - การผลิต 64 บิต
  • ขั้นตอนดำเนินการผ่าน Microsoft.Practices.EnterpriseLibrary - Data.Oracle.OracleDatabase.ExecuteReader (คำสั่ง DbCommand)
  • แอปพลิเคชันไม่รวมการโทรในธุรกรรมที่ชัดเจน
  • การแทรกล้มเหลวเป็นระยะ - น้อยกว่า 1%

ภายใต้สถานการณ์ใดที่อาจx_seq.nextvalเป็นโมฆะ?


รหัสอยู่ระหว่างการเลือก & แทรกจำนวนเท่าใด มี BEGIN .. END บล็อกหรือคำสั่งยกเว้นใด ๆ ในรหัสนั้นหรือไม่ v_id ถูกอ้างถึงในรหัสนั้นหรือไม่? ดูเหมือนจะแปลกไปหน่อย คุณสามารถวาง "IF v_id เป็นโมฆะแล้ว ... END IF" บล็อกโดยตรงหลังจากคำสั่งและออกจากการแก้จุดบกพร่องบางอย่างถ้าเรียงลำดับในความเป็นจริงจะกำหนด null ให้ v_id? หรือตัดลำดับให้เลือกในบล็อก BEGIN .. EXCEPTION เนื่องจากอาจมีบางสิ่งที่เกิดขึ้นที่ไม่ถูกดักจับ สิ่งสุดท้ายสิ่งหนึ่ง - มีทริกเกอร์บนโต๊ะที่คุณกำลังแทรกเข้าไป
Philᵀᴹ

@Phil - การเลือกทันทีก่อนการแทรก ไม่มี BEGIN, END หรือ EXCEPTION นอกเหนือจาก proc BEGIN / END v_idอ้างอิงเฉพาะในการเลือกลำดับการแทรกและเคอร์เซอร์สุดท้าย ขั้นตอนต่อไปของเราคือการเพิ่มรหัสการแก้จุดบกพร่อง เราอาจต้องรอผลเพราะมันเกิดขึ้นในการผลิตและไม่บ่อยนัก มีทริกเกอร์ที่แทรกเข้าไปในตารางการตรวจสอบ ฉันหวีมันโดยไม่มีปืนสูบบุหรี่ ปัญหานี้ยังเกิดขึ้นในตารางอื่นเป็นครั้งคราวโดยไม่มีทริกเกอร์ ขอบคุณสำหรับการดู
Corbin วันที่

5
สิ่งเดียวที่ฉันคิดได้ในตอนนี้ก็คือถ้า: new_the_id จะกลายเป็นค่า NULL ในทริกเกอร์ที่อยู่บนโต๊ะ X
Philᵀᴹ

@ ฟิล: นี่เป็นสาเหตุของปัญหาอย่างแน่นอน คุณควรให้คำตอบ
René Nyffenegger

@ RenéNyffenegger - ปัญหาเกิดขึ้นใน procs ที่แทรกลงในตารางโดยไม่มีทริกเกอร์ มันดูเหมือนจะเป็นข้อผิดพลาดโอกาสที่เท่าเทียมกัน
Corbin วันที่

คำตอบ:


4

ฉันค่อนข้างแน่ใจว่านี่จะเป็นสิ่งประดิษฐ์ของรหัสของคุณหรือไดรเวอร์. net ที่คุณใช้ ฉันทำให้การสาธิตอย่างรวดเร็วสำหรับคุณโดยใช้ SQL บริสุทธิ์ - PL / SQL และไม่ได้รับค่าลำดับที่หายไป บังเอิญเคอร์เซอร์อ้างอิงที่คุณใช้อาจไม่จำเป็นและอาจส่งผลกระทบต่อประสิทธิภาพและความสามารถในการอ่านรหัส - การสาธิตของฉันมีขั้นตอน insert_record2 ซึ่งทำงานได้เร็วกว่า 10% อย่างต่อเนื่อง อย่างน้อยฉันก็คิดว่าเข้าใจง่ายกว่า เห็นได้ชัดว่าคุณสามารถรันเวอร์ชันที่ถูกแก้ไขกับฐานข้อมูลการทดสอบของคุณพร้อมด้วยทริกเกอร์การตรวจสอบ

/* 
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
โดยวิธีการรุ่นด้วยวิธีการดั้งเดิมของการใช้ทริกเกอร์สำหรับคอลัมน์ the_id และขั้นตอนดังต่อไปนี้ยังรันการสร้างหรือแทนที่ PROCEDURE Insert_Record3 ที่รวดเร็วกว่า (p_name IN dbse13142.name% type, p_userid IN dbse13142.userid% type, p_theid OUT dbse13142.userid% .the_id% type) เป็น BEGIN INSERT INTO dbse13142 (ชื่อ, หมายเลขผู้ใช้) ค่า (p_name, p_userid) ส่งคืนค่า theid ไปยัง p_theid; END; /
Niall Litchfield

ยอมรับว่าอาจเป็นปัญหากับรหัสแอพหรือไดรเวอร์ ฉันแค่อยากรู้ว่าสิ่งใดที่อาจทำให้เกิดค่าว่างถัดไปเป็นผลข้างเคียง ทำให้งง ขอบคุณสำหรับเคล็ดลับประสิทธิภาพ เป็นคำแนะนำที่ดีที่ฉันจะแนะนำให้กับทีม
Corbin วันที่

1
Corbin สิ่งที่ฉันหมายถึง (และ Kevin) ก็คือมีสิ่งผิดปกติเกิดขึ้นระหว่างรหัสและ oracle ของคุณ - ถ้าคุณทำการทดสอบใน SQL อย่างแท้จริงคุณจะไม่ได้รับผลกระทบใด ๆ แต่เห็นความคิดเห็นของ Phil เกี่ยวกับทริกเกอร์การตรวจสอบ (ซึ่งคุณสามารถลองปิดการใช้งาน)
Niall Litchfield

ฉันเข้าใจประเด็นที่ทำ ปัญหามีอยู่ใน procs การแทรกลงในตารางที่มีและไม่มีทริกเกอร์ดังนั้นจึงไม่จำเป็นต้องมีทริกเกอร์ เมื่อมีทริกเกอร์มันจะแทรกเข้าไปในตารางการตรวจสอบ ฉันยืนยันว่า:new.the_idไม่มีใครแตะต้อง ฉันเข้าใจคำถามของฉันเป็นระยะเวลานาน มันทนต่อ google-fu ของฉันและมีคนหลายคนเกาหัวของพวกเขาที่นี่ ฉันเพิ่งคิดว่าบางคนอาจรับรู้ถึงอาการ (และการรักษา) ที่ได้รับลูกตาที่เพียงพอ ขอบคุณสำหรับการดู
Corbin วันที่

2

ลองทำกรณีทดสอบ สร้างตารางจำลองและแทรก 100,000 ระเบียนโดยใช้ลำดับของคุณจากฐานข้อมูล ฉันเดิมพันคุณจะไม่มีปัญหา จากนั้นให้ลองแทรกสิ่งเดียวกันจากแอปพลิเคชันของคุณ

สิ่งนี้อาจเกิดจากปัญหาอื่น ๆ เช่นลูกค้า Oracle ไม่ตรงกันหรือไม่?

วิธีแก้ไขปัญหาอื่นที่จะแก้ไขปัญหา แต่ไม่มีปัญหาคือการเพิ่มทริกเกอร์บนตาราง
ก่อนที่จะแทรกบนโต๊ะใน Dallas.X ถ้า: the_id เป็นโมฆะจากนั้นเลือก x_seq.nextval INTO: the_id จาก dual; สิ้นสุดถ้า;


ฉันไม่สามารถสร้างปัญหาขึ้นใหม่ในพื้นที่ได้ มันเกิดขึ้นในการผลิตและมีไม่บ่อยนัก ลางสังหรณ์ของฉันคือคุณถูกต้องเกี่ยวกับไคลเอนต์ Oracle ปัญหานี้เกิดขึ้นเมื่อสองสามสัปดาห์ที่ผ่านมาในระหว่างการวางจำหน่ายซึ่งลูกค้าไม่ได้รับการอัพเดต อย่างไรก็ตามมันรู้สึกว่ามีบางอย่างไม่เข้ากันระหว่างแอพและฐานข้อมูล ปฏิสัมพันธ์จากผู้บริโภครายอื่นดูเหมือนจะทำงานได้ดี การตรวจสอบโมฆะไม่ใช่ความคิดที่ไม่ดี แต่โดยหลักแล้วฉันต้องการทราบจุดเริ่มต้นของปัญหาเมื่อเทียบกับการแก้ไข ใครจะรู้บ้าง การแก้ไขโดยรอบดีกว่าเสีย
Corbin วันที่

0

ฉันยังไม่มี priveldges ที่จะแสดงความคิดเห็นดังนั้นให้เขียนคำตอบนี้: เนื่องจากคุณใช้ Oracle เวอร์ชัน> = 11.1 ซึ่งอนุญาตให้ลำดับในการแสดงออก PL / SQLแทนที่จะเป็นใน SQL ลองสิ่งนี้:

   v_id := x_seq.nextval;

แทนสิ่งนี้:

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

หรือแม้ว่าฉันเคยได้ยินข้อสงสัย / ข้อผิดพลาดเมื่อใช้ ".currval" อาจละเว้นการมอบหมาย v_id แยกต่างหากและใช้รหัสนี้เท่านั้น:

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

ขออภัยฉันไม่มีอินสแตนซ์ 11g ที่มีประโยชน์ในตอนนี้เพื่อลองใช้


มันทำให้ไม่มีความแตกต่างแน่นอน ฉันใช้งานselect into...11 เท่าใน 9i และ 10g ประโยชน์เพียงอย่างเดียวจาก 11+ สามารถอ้างอิงได้อย่างชัดเจนตามที่คุณได้ชี้ให้เห็น
เบ็น
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.