21 rules for faster queries (part 2)

01-Aug-17

คัมภีร์เทพ IT

        ครั้งที่แล้ว ทีมงาน TechStar ได้นำเสนอ SQL เทคนิคตอนที่ 1 ไปแล้ว 10 ข้อ วันนี้มาต่อตอนที่ 2 กันอีก 11 ข้อที่เหลือกันต่อ (ส่วนใครยังไม่ได้อ่าน 10 ข้อแรก ย้อนกลับไปดูได้ ที่นี่) เรามาดูกันเลยว่าอีก 11 ข้อมีเทคนิคอะไรบ้าง

 

  1. เลี่ยงการใช้ ORM
    อันที่จริงแล้ว Object-relational mappers (ORMs) เป็นการเขียน Code เพื่ออำนวยความสะดวกในการแปลงจาก Object ไปเป็น Database หรือแปลงจาก
    Database กลับมาเป็น Object โดยไม่ต้องยุ่งกับในส่วนของ SQL เลย แต่ขณะเดียวกัน มันก็ส่งผลกระทบต่อ Performance โดยรวมได้ และอาจดูไม่ค่อยจำเป็นเท่าไหร่ แต่หากคุณจำเป็นต้องใช้ ORM แนะนำให้ใช้ Stored Procedures แล้วให้ ORM มาเรียกมันใช้งานแทนการใช้ ORM แบบตรงๆ
  2. Stored Procedure มีประโยชน์หลายอย่าง
    นอกจากจะทำให้ตัว Code มีประสิทธิภาพแล้ว ยังมีข้อดีอีกหลายอย่าง ทั้งช่วยลด Traffic ของ Network หรือระหว่าง Database กับ Application และง่ายในการติดตามข้อมูล โดยการใช้ Tool อย่างเช่น Profiler ซึ่งช่วยให้คุณได้ทราบสถิติต่างๆ ได้อย่างมีประสิทธิภาพ รวมทั้งระบุปัญหาที่อาจเกิดขึ้นได้รวดเร็วขึ้น นอกจากนี้ ยังเหมาะกับการเรียกใช้ข้อมูลซ้ำๆ ด้วย มี .Net Developer หลายคนมักให้ความสำคัญกับการพัฒนาตัว Front end ของ App ให้สอดคล้องกับความต้องการของธุรกิจมากกว่าให้ความสำคัญกับ Database ซึ่งในความเป็นจริงแล้ว เป็นความคิดที่ไม่ถูกต้องสักเท่าไรนัก

     
  3. หลีกเลี่ยงการเกิด Double-Dipping
    บางกรณีการใช้งาน Stored Procedure ก็อาจทำให้เกิด Double-Dipping ได้เช่นกัน หากคุณต้องการ Query ข้อมูล จาก Table ใหญ่ๆ หลายๆ ครั้ง แล้วไปใส่ในแต่ละ Temp Table จากนั้นเอา Table ทั้งหลายเหล่านั้นมา Join กันอีก การทำแบบนี้ เป็นการทำให้ Performance แย่ลง แต่มีวิธีที่ดีกว่าคือ ควรหลีกเลี่ยงการ Query ข้อมูลจาก Table ขนาดใหญ่หลายๆ ครั้ง แต่ควรจะ Query ข้อมูลมาจาก Table ใหญ่นั้น ให้มีขนาดข้อมูลที่เล็กลง แล้วค่อยดำเนินการอะไรก็ตามกับข้อมูลเหล่านั้นจะดีกว่า

     
  4. แยก Transaction ใหญ่ๆ ให้เล็กลง
    การดำเนินการอะไรก็ตามกับหลายๆ Table พร้อมๆ กันภายใน Transaction เดียว จะทำให้ Table เหล่านั้นจะถูก Lock จนกว่าจะดำเนินการ Transaction นั้นสำเร็จ ทางแก้ปัญหาจากกรณีแบบนี้คือ ควรแบ่งเป็น Transaction ย่อยๆ แทน โดยพยายามให้เหลือ 1 Operation ต่อ Table แล้วค่อยๆ ทะยอยดำเนินการไปในแต่ละ Table การทำแบบนี้เพื่อช่วยให้ Table อื่นที่ไม่ถูก Operation จะได้ไม่ถูก Block ไปด้วย

     
  5. ระมัดระวังการใช้ Trigger
    การใช้ Trigger ก็อาจจะเกิดปัญหาในลักษณะเดียวกับหัวข้อที่แล้วได้เช่นกัน คือระว่างใช้ Trigger มันจะ Lock ตัว Table ที่เกี่ยวข้องจนกว่าจะดำเนินการ Transaction นั้นสำเร็จ ทางแนะนำก็คือ ทำเป็น Trigger ย่อยๆ สำหรับแต่ละ Table ซึ่งมันจะใช้งาน Resource ต่างๆ น้อยลงและถ้าจะ Roll back ข้อมูล ก็สามารถทำได้ง่ายกว่าด้วย  อันที่จริง ในหลายกรณีก็ไม่จำเป็นต้องใช้ Trigger ก็ได้

     
  6. หลีกเลี่ยงการใช้ GUIDs
    พยายามหลีกเลี่ยงการใช้ Globally Unique Identifiers (GUIDs) ในการ Order (จัดเรียง) ข้อมูลใน Table  เพราะตัวเลข 16 บิตที่ถูกสร้างขึ้น “แบบ Random” ของ GUID อาจทำให้เกิดปัญหากับ Table ได้มากขึ้น ควรใช้การ Order ข้อมูลโดยใช้ค่าที่เฉพาะเจาะจงไปเลย เช่น DATE หรือ IDENTITY เป็นต้น จะช่วยลดการเกิดปัญหาของ Table

     
  7. อย่าใช้คำสั่ง COUNT กับข้อมูลทั้งหมดใน Table
    สมมติคุณต้องการดูข้อมูลบางอย่างว่า มีอยู่ใน Table นั้นไหม เช่น อยากเช็คข้อมูลของลูกค้า แน่นอนว่าคุณต้อง Query ข้อมูลจาก Table ออกมา แต่เชื่อไหมว่ามีบางคนที่ใช้คำสั่ง SELECT COUNT(*) FROM dbo.T1 เพื่อเช็คข้อมูลว่ามีอยู่ไหม ลองดูจากตัวอย่าง

    SET @CT = (SELECT COUNT(*) FROM dbo.T1);
    If @CT > 0
    BEGIN <Do something>
    END

    แน่นอนว่าได้ข้อมูล แต่ก็ไม่เห็นจำเป็นต้องทำถึงขนาดนั้น ถ้าอยากจะเช็ค ก็ลองทำแบบนี้ดู:

    If EXISTS (SELECT 1 FROM dbo.T1)
    BEGIN
    <Do something>
    END

    กล่าวคือ เราไม่ควรใช้ Count(*) อย่างพร่ำเพรื่อ หากเราต้องการแค่เช็คข้อมูลที่เราสนใจ ก็เพียงดึงข้อมูล Row นั้นออกมาเท่านั้นเอง อย่างใน SQL Server เองก็สามารถใช้คำสั่ง EXISTS เข้ามาช่วยได้ โดยจากตัวอย่างที่ 2 คุณจะได้ผลลัพธ์ที่รวดเร็วกว่าตัวอย่างแรกมาก

     
  8. ใช้ System Table ในการนับแถวข้อมูล
    Rows) ของข้อมูลใน Table ที่มีขนาดใหญ่ๆ สามารถใช้คำสั่ง SELECT rows from sysindexes เพียงเท่านี้ คุณก็จะได้จำนวนแถว Index ทั้งหมด และเนื่องจากกลุ่ม Index เองก็เป็นข้อมูลอยู่แล้ว คุณสามารถทราบจำนวน Rows ของ Table ด้วยการเพิ่มเงื่อนไข WHERE indid = 1 เข้าไป จากนั้นก็ใส่ชื่อ Table และคุณก็จะได้ข้อมูลที่ต้องการ โดยคุณสามารถใช้คำสั่ง Query ดังนี้ SELECT rows FROM sysindexes WHERE object_name(id) = ‘T1’ AND indid = 1

     
  9. ควรดึงเฉพาะ Column ที่ต้องการเท่านั้น
    มันอาจจะดูง่าย แค่ใช้คำสั่ง SELECT * แทนที่จะดึง Column ทีละรายการ เมื่อทำแบบนี้มีปัญหาคือ คุณจะได้ข้อมูลที่ไม่ต้องการออกมาด้วย คิดดูหากคุณใช้คำสั่ง SELECT * ใน Table ที่มี 120 Columns และมีจำนวนแถวเป็นล้านๆ Rows แต่ข้อมูลที่คุณต้องการใช้จริง มีเพียง 3 – 5 รายการเท่านั้น ผลคือ ไม่เพียงต้องประมวลผลข้อมูลในจำนวนมหาศาลเท่านั้น แต่ยังกิน Resource ของระบบไปมากมายโดยไม่จำเป็นอีกด้วย

     
  10. เขียน Query ใหม่เพื่อเลี่ยงผลกระทบในการ Search ข้อมูล
    หากคุณต้องการเปรียบเทียบข้อมูลแต่ละแถว(Row) กรณีที่ไม่สามารถใช้ Index เช่น SELECT * FROM Customers WHERE RegionID <> 3 แต่มันจะดีกว่าหากเขียน Query ซะใหม่โดยที่สามารถใช้การ Index เพื่อช่วยในการค้นหาข้อมูลได้ โดยแก้ไขเป็น SELECT * FROM Customers WHERE RegionID < 3 UNION ALL SELECT * FROM Customers WHERE RegionID > 3 กรณีที่ชุดข้อมูลมีขนาดใหญ่มากๆ การใช้ Index จะสามารถค้นหาได้ดีกว่าการ Scan ข้อมูลใน Table แต่ทางที่ดีคุณควรทดสอบก่อนจะ Implement เสมอ และหากคุณสังเกตดีๆ จะพบว่า มันขัดแย้งกับกฏในข้อ 13 (หลีกเลี่ยงการเกิด Double-Dipping) อยู่ แต่มันก็สะท้อนเห็นเช่นกันว่า ไม่มีเทคนิคใดที่ใช้ได้ในทุกกรณีเสมอไป แม้ว่าจะเกิด Double-Dipping ในครั้งนี้ แต่เราก็ยังคงทำเพื่อหลีกเลี่ยงการที่ต้อง Scan ข้อมูลทั้ง Table นั่นเอง สิ่งสำคัญที่สุดคือ เราควรเลือกวิธีที่เหมาะสมมากกว่า อย่ายึดแต่หลักการเพียงอย่างเดียว

     
  11. อย่านำ Code (คน)อื่น มาใช้แบบสุ่มสี่สุมห้า
    มันเป็นเรื่องง่ายมากในการ Copy Code ของคนอื่นมาใช้งาน เมื่อคุณเห็นว่ามันดึงข้อมูลในลักษณะเดียวกันมาให้คุณได้ แต่ปัญหาคือ การทำแบบนี้ คุณมักจะได้ข้อมูลที่คุณไม่ต้องการออกมาด้วย และเหล่า Developer ก็มักไม่ค่อยให้ความสำคัญในการตัดสิ่งไม่จำเป็นพวกนั้นออกซะด้วยสิ สุดท้ายคุณก็ได้ข้อมูลที่ไม่จำเป็นออกมามากมาย โดยที่มาของผลลัพธ์ที่ไม่จำเป็นดังกล่าว มักเกิดจากการใช้ OUTER JOIN หรือเงื่อนไขพิเศษต่างๆ ใน WHERE clause ซึ่งคุณสามารถแก้ไขปัญหานี้ได้โดยการใช้เฉพาะ Code ที่ตรงกับความต้องการของคุณเท่านั้นเอง

 

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

 

ที่มาinfoworld.com

 

อัพเดทบทความจากคนวงในสายไอทีทาง LINE ก่อนใคร
อย่าลืมแอดไลน์ @techstarth เป็นเพื่อนนะคะ

 

เพิ่มเพื่อน

 

 

 

บทความที่เกี่ยวข้อง