เหตุใดจึงใช้เคอร์เซอร์ที่ชัดเจนแทนการวนซ้ำปกติ


12

ฉันได้เขียนเว็บแอพพื้นฐานเป็นเวลาหนึ่งปี (สำหรับฐานข้อมูล Oracle) และเนื่องจากฟังก์ชั่นนั้นค่อนข้างเรียบง่ายพวกเราส่วนใหญ่ติดอยู่กับ FOR ลูปปกติเพื่อรับข้อมูลของเรา:

for i in (select * from STUDENTS) loop
      htp.prn(i.student_last_name || ', ' || i.student_first_name || ' ' || i.student_dob);
end loop;

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


ประเภทนี้FORเป็นอีกวิธีหนึ่งในการใช้เคอร์เซอร์ ดูเอกสาร: docs.oracle.com/cd/E11882_01/appdev.112/e10472/… อย่างไรก็ตาม htp.prn () ทำอะไร
dezso

นั่นเป็นหนึ่งในฟังก์ชั่นการส่งออกของเรา ดังนั้นคุณมีความพึงพอใจกับวิธีการที่จะใช้หรือไม่?
ini

สำหรับสิ่งประเภทนี้การFORวนซ้ำสามารถอ่านได้มากขึ้นฉันคิดว่า ฉันมักจะใช้เคอร์เซอร์ 'ของจริง' เท่านั้นหากฉันต้องถอยหลังไปข้างหน้าไม่ใช่แค่ส่งต่อ ผมถามว่าคำถามอื่น ๆ htp.prn()เพราะฉันสามารถจินตนาการฟังก์ชันตารางแทน
dezso

เป็นเรื่องที่ควรกล่าวถึงว่าเคอร์เซอร์ทั้งสองรูปแบบมีประสิทธิภาพด้อยกว่าสำหรับโซลูชัน SQL ล้วนๆโดยเฉพาะที่เกี่ยวข้องกับคำสั่ง DML
David Aldridge

คำตอบ:


7

เคอร์เซอร์สามารถชัดเจนหรือโดยนัยและทั้งสองประเภทสามารถใช้ในการวนรอบ FOR คำถามของคุณมีสองด้านจริงๆ

  1. เหตุใดจึงต้องใช้เคอร์เซอร์ชัดเจนสำหรับการวนรอบเคอร์เซอร์โดยนัยสำหรับการวนลูป?

    • ใช้เคอร์เซอร์ชัดเจนสำหรับวงเมื่อแบบสอบถามจะถูกนำมาใช้มิฉะนั้นเคอร์เซอร์โดยนัยเป็นที่ต้องการ
  2. เหตุใดจึงใช้การวนซ้ำกับ FETCH แทนการวนซ้ำสำหรับ FOR ที่ไม่มี FETCH ชัดเจน

    • ใช้ FETCH ภายในลูปเมื่อคุณต้องการรวบรวมเป็นกลุ่มหรือเมื่อคุณต้องการ SQL แบบไดนามิก

นี่คือข้อมูลที่มีประโยชน์จากเอกสาร

ตัวอย่างของเคอร์เซอร์โดยนัยสำหรับ LOOP

BEGIN
   FOR vItems IN (
      SELECT last_name
      FROM employees
      WHERE manager_id > 120
      ORDER BY last_name
   ) 
   LOOP
      DBMS_OUTPUT.PUT_LINE ('Name = ' || vItems.last_name);
   END LOOP;
END;
/

ตัวอย่างของเคอร์เซอร์อย่างชัดเจนสำหรับ LOOP

DECLARE
   CURSOR c1 IS
      SELECT last_name
      FROM employees
      WHERE manager_id > 120
      ORDER BY last_name;
BEGIN
   FOR vItems IN c1 LOOP
      DBMS_OUTPUT.PUT_LINE ('Name = ' || vItems.last_name);
   END LOOP;
END;
/

เคอร์เซอร์โดยนัย

เคอร์เซอร์โดยนัยคือเคอร์เซอร์เซสชันที่สร้างและจัดการโดย PL / SQL PL / SQL เปิดเคอร์เซอร์โดยนัยทุกครั้งที่คุณเรียกใช้คำสั่ง SELECT หรือ DML คุณไม่สามารถควบคุมเคอร์เซอร์โดยนัย แต่คุณสามารถรับข้อมูลจากแอททริบิวของมันได้

เคอร์เซอร์โดยปริยายปิดหลังจากคำสั่งที่เกี่ยวข้องทำงาน อย่างไรก็ตามค่าแอททริบิวของมันจะยังคงอยู่จนกว่าจะมีคำสั่ง SELECT หรือ DML อื่นรัน

แอตทริบิวต์ของเคอร์เซอร์โดยนัยคือ: SQL% ISOPEN, SQL% FOUND, SQL% NOTFOUND, SQL% ROWCOUNT, SQL% BULK_ROWCOUNT, SQL% BULK_EXCEPTIONS

เคอร์เซอร์อย่างชัดเจน

เคอร์เซอร์ที่ชัดเจนคือเคอร์เซอร์เซสชันที่คุณสร้างและจัดการ คุณต้องประกาศและกำหนดเคอร์เซอร์ที่ชัดเจนโดยตั้งชื่อและเชื่อมโยงกับแบบสอบถาม (โดยทั่วไปแล้วแบบสอบถามจะส่งกลับหลายแถว) จากนั้นคุณสามารถประมวลผลผลลัพธ์แบบสอบถามที่ตั้งค่าด้วยวิธีใดวิธีหนึ่งต่อไปนี้:

เปิดเคอร์เซอร์ที่ชัดเจน (ด้วยคำสั่ง OPEN) ดึงแถวจากชุดผลลัพธ์ (ด้วยคำสั่ง FETCH) และปิดเคอร์เซอร์ที่ชัดเจน (ด้วยคำสั่ง CLOSE)

ใช้เคอร์เซอร์ที่ชัดเจนในเคอร์เซอร์สำหรับคำสั่ง LOOP (ดูที่ "การประมวลผลชุดผลลัพธ์แบบสอบถามด้วยเคอร์เซอร์สำหรับคำสั่ง LOOP")

คุณไม่สามารถกำหนดค่าให้กับเคอร์เซอร์ที่ชัดเจนใช้ในนิพจน์หรือใช้เป็นพารามิเตอร์โปรแกรมย่อยอย่างเป็นทางการหรือตัวแปรโฮสต์ คุณสามารถทำสิ่งเหล่านั้นด้วยตัวแปรเคอร์เซอร์ (ดูที่ "ตัวแปรเคอร์เซอร์")

ไม่เหมือนกับเคอร์เซอร์โดยปริยายคุณสามารถอ้างอิงเคอร์เซอร์หรือตัวแปรเคอร์เซอร์ที่ชัดเจนโดยใช้ชื่อ ดังนั้นเคอร์เซอร์หรือตัวแปรเคอร์เซอร์ที่ชัดเจนจึงเรียกว่าเคอร์เซอร์ที่มีชื่อ

เคอร์เซอร์สำหรับข้อความลูป

เคอร์เซอร์สำหรับคำสั่ง LOOP ช่วยให้คุณเรียกใช้คำสั่ง SELECT แล้ววนซ้ำแถวต่างๆของชุดผลลัพธ์ทันที คำสั่งนี้สามารถใช้เคอร์เซอร์โดยนัยหรือชัดเจน


1
เคอร์เซอร์โดยปริยายเรียก 100 แถวในเวลาตั้งแต่ 10g เป็นต้นไป
David Aldridge

16

รหัสที่คุณโพสต์กำลังใช้เคอร์เซอร์ มันใช้การวนรอบเคอร์เซอร์โดยปริยาย

มีหลายกรณีที่ใช้เคอร์เซอร์ลูปที่ชัดเจน (เช่นการประกาศตัวแปรเคอร์เซอร์ในส่วนการประกาศ) สร้างโค้ดที่สะอาดขึ้นหรือประสิทธิภาพที่ดีขึ้น

  1. หากคุณมีคิวรีที่ซับซ้อนมากขึ้นซึ่งคุณไม่สามารถกำหนดโครงสร้างซ้ำในมุมมองได้ก็สามารถทำให้โค้ดอ่านง่ายขึ้นถ้าลูปวนซ้ำ student_cursorแทนที่จะรวมคำสั่ง SQL 30 บรรทัดที่รวมตรรกะเข้าด้วยกัน ตัวอย่างเช่นหากคุณกำลังพิมพ์นักเรียนที่จบการศึกษาและเกี่ยวข้องกับการเข้าร่วมตารางที่มีบันทึกการศึกษาข้อกำหนดของหลักสูตรปริญญาของพวกเขาตารางที่มีข้อมูลเกี่ยวกับการศึกษาทางวิชาการตารางที่มีข้อมูลเกี่ยวกับหนังสือห้องสมุดที่ค้างชำระ ตารางที่มีข้อมูลเกี่ยวกับค่าธรรมเนียมที่ยังไม่ได้ชำระการแทนที่การดูแลระบบเป็นต้นอาจเป็นเหตุผลที่จะต้องปรับรหัสให้ใหม่เพื่อที่ว่าแบบสอบถามนี้จะไม่ติดอยู่ตรงกลางของรหัสที่เกี่ยวข้องกับการนำเสนอรายการต่อผู้ใช้ ที่อาจเกี่ยวข้องกับการสร้างมุมมองที่จะแค็ปซูลตรรกะทั้งหมดนี้ หรืออาจเกี่ยวข้องกับการสร้างเคอร์เซอร์ที่ชัดเจนซึ่งถูกประกาศว่าเป็นส่วนหนึ่งของบล็อก PL / SQL ปัจจุบันหรือในบล็อก PL / SQL ระดับสูงกว่า (เช่น เคอร์เซอร์ที่ประกาศในแพ็คเกจ) เพื่อให้สามารถใช้ซ้ำได้ หรืออาจเกี่ยวข้องกับการทำอย่างอื่นเพื่อการห่อหุ้มและการนำกลับมาใช้ใหม่ (เช่นการสร้างฟังก์ชันตาราง pipelined แทน)
  2. หากคุณต้องการใช้ประโยชน์จากการดำเนินงานจำนวนมากใน PL / SQL โดยทั่วไปคุณต้องการใช้เคอร์เซอร์อย่างชัดเจน นี่คือด้าย StackOverflow ที่กล่าวถึงความแตกต่างระหว่างประสิทธิภาพเคอร์เซอร์ชัดเจนและโดยนัย หากสิ่งที่คุณกำลังทำอยู่คือการโทรhtp.prnการBULK COLLECTซื้ออาจจะไม่ได้ซื้ออะไรให้คุณ ในกรณีอื่น ๆ อาจส่งผลให้มีการปรับปรุงประสิทธิภาพอย่างมาก

2

ฉันเห็นว่านักพัฒนาหลายคนใช้เคอร์เซอร์ชัดเจนแทนเคอร์เซอร์โดยปริยายจากนิสัยเก่า เนื่องจากย้อนกลับไปใน Oracle เวอร์ชัน 7 นี่เป็นวิธีที่มีประสิทธิภาพมากกว่าเสมอ ทุกวันนี้มักจะมีวิธีอื่น ๆ พิเศษด้วยเครื่องมือเพิ่มประสิทธิภาพที่หากจำเป็นอาจเขียนเคอร์เซอร์โดยนัยสำหรับลูปไปที่การรวบรวมจำนวนมาก


0

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

เราได้รับคำแนะนำให้เขียนทุกอย่างใหม่โดยใช้เคอร์เซอร์อย่างชัดเจนและข้อผิดพลาดนั้นหายไป

ไม่ใช่เหตุผลหลักที่คุณอาจต้องการใช้อย่างชัดเจนเหนือสิ่งอื่นโดยนัย แต่ควรทราบด้วย

แก้ไข: Oracle 12c


คุณสามารถเพิ่มในข้อผิดพลาดและ / หรือหมายเลขบันทึกเพื่อให้ผู้อ่านนี้สามารถทราบเพิ่มเติมเกี่ยวกับอาการและถ้า / เมื่อได้รับการแก้ไข?
Leigh Riffel

ขออภัยการรายงานข้อผิดพลาดทำโดยหนึ่งใน DBA ของเราฉันไม่สามารถเข้าถึงข้อมูลนั้นได้
Robotron
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.