เทคนิคในการ Tuning เพื่อให้ SQL ที่เขียนนั้นมีประสิทธิภาพสูงสุดนั้น มีหลากหลาย ซึ่งขึ้นอยู่กับความถนัดและสถานการณ์นั้น หนึ่งในสิ่งที่ผมต้องคำึนึงเสมอก็คือ Context Switch อย่างที่เราทราบกันดีกว่า ใน Oracle มี Engineที่ใช้ในการ Process PL/SQL Statement มี 2 Engine คือ PL/SQL Engine และ SQL Engine เมื่อเราเขียน คำสั่ง PL/SQL เช่น สร้าง Cursor ซึ่งเป็นวิธีที่ Programmer มื่อใหม่ (รวมถึงผมเองด้วย ) ชอบใช้เขียนเพื่อดึงข้อมูลเยอะๆมาแสดงผลหรือ Process ต่อไป โดยทีไม่รู้ หรือไม่ได้ระวังถึงผลที่กระทบกับเรื่อง Performance (ก็ตอน Develop ข้อมูลมันหลัก 10 หรือ100 records แต่งานจริง อย่างน้อยก็หลัก หมื่นหรือหลักแสน records )
sql > create table t as select * from all_objects where 0 =1 ; sql> set timing on ต.ย. การสร้าง Cursor BEGIN FOR x IN (SELECT * FROM all_objects) LOOP INSERT INTO t (owner, object_name, subobject_name, object_id, data_object_id, object_type, created, last_ddl_time, timestamp, status, temporary, generated, secondary,namespace,edition_name) VALUES (x.owner, x.object_name, x.subobject_name, x.object_id, x.data_object_id, x.object_type, x.created, x.last_ddl_time, x.timestamp, x.status, x.temporary, x.generated, x.secondary,x.namespace , x.edition_name); END LOOP; COMMIT; END; เวลาที่ใช้ คือ 17.56 วินาที ได้ข้อมูล 68,440 records การทำงานของ Cursor คือ fetch c_data ทีละ record จนจบ และในขณะที่ Cursor fetch ข้อมูลนั้นเอง ทำให้เกิด Context Switch ขึ้น และปกติแล้ว Context Switch เกิดขึ้นอย่างรวดเร็วมาก(ประมาณ 1/1000 วินาที) แต่ปัญหาคือ เกิดขึ้นเยอะมาก เช่น Cursor ที่มีข้อมูล 100,000 record เิิกิด Context Switch 100,000 ครั้ง และนี่ก็คือ เวลาที่เสียไปโดยเปล่าประโยชน์จริงๆ Context Switch จึงเป็นปัญหาสำคัญของ Performance ถ้าลองคิดดูว่า ข้อมูลที่เพิ่มขึ้นทุกๆวัน หลังจากถูกใช้งาน ถ้ามีการเขียน Code โดยไม่คำนึงถึงปัญหาเหล่านี้ เราจึงพบปัญหาว่า หลังจากใช้งานจริง ระบบทำงานช้าลง สุดท้ายก็ต้องให้ DBA มา Tune Database ให้ แต่จริงๆ แล้ว สา่เหตุที่เกิดจากการ Code ที่เขียนโดยรู้เท่าไม่ถึงการณ์ ดังนั้น ทางออกของปัญหานี้ ก็คือ การลดจำนวน Context Switch หลักการง่ายๆ ก็คือ กรณีที่ต้อง Preocess กับ ข้อมูลเยอะๆ ให้ใช้คำสั่งที่ทำกับข้อมูลที่ละ หลายๆ record ได้ เช่น Forall , bulk collect ต.ย. bulk collect ทำทีละ 10,000 records sql > create table t2 as select * from all_objects where 0 =1 ;
sql >DECLARE TYPE ARRAY IS TABLE OF all_objects%ROWTYPE; all_data ARRAY; CURSOR c_all IS SELECT * FROM all_objects; BEGIN OPEN c_all; LOOP FETCH c_all BULK COLLECT INTO all_data LIMIT 10000; FORALL i IN 1..all_data.COUNT INSERT INTO t2 VALUES all_data(i); EXIT WHEN c_all%NOTFOUND; END LOOP; CLOSE c_all; END ; เวลาที่ใช้คือ 11.68 วินาที ได้ข้อมูล 68,440 records จาก 2 ตัวอย่่างจะเห็นได้ว่า เวลาต่างกันพอสมควร เมื่อเทียบเป็นเปอร์เซ็นต์ ผลต่างของ Context Switch ยิ่งเห็นได้ชัดขึ้นเมื่อข้อมูลเยอะขึ้น เป็นหลักล้าน ซึ่งเป็นไปได้เมื่อมีการ Join เช่้น table 3 table join กัน โดยมี data 10,000 x 1,000 x 10 = 10,000,000 = 10 ล้าน ลักษณะนี้มีโอกาสเป็นไปได้มากทีเดียว เล็กๆ น้อยๆ กับเวลาที่เสียไป แต่เมื่อทำบ่อยๆ เวลาที่เสียไปอาจจะมากจนคิดไม่ถึงทีเดียว เหมือนกับ เรื่องของการดูแลสิ่งแวดล้อม ลดขยะ ลดพลาสติก ใช้ไฟให้น้อยลงคนละ 1 ดวง เพียงแค่นี้ก็เป็นการเริ่มต้นช่วยสิ่งแวดล้อมโลกได้มากทีเดียวครับ |