นักพัฒนาถกเถียงการย้ายการปรับแต่งฐานข้อมูลเข้าไปในภาษาโปรแกรมเพื่อแก้ปัญหา N+1 Query

ทีมชุมชน BigGo
นักพัฒนาถกเถียงการย้ายการปรับแต่งฐานข้อมูลเข้าไปในภาษาโปรแกรมเพื่อแก้ปัญหา N+1 Query

ชุมชนนักพัฒนาโปรแกรมกำลังหารือกันอย่างกระตือรือร้นเกี่ยวกับแนวทางที่กล้าหาญในการแก้ไขปัญหาประสิทธิภาพฐานข้อมูลที่พบบ่อยที่สุดอย่างหนึ่ง นั่นคือปัญหา N+1 query แทนที่จะใช้วิธีแก้ไขแบบดั้งเดิมที่ต้องให้นักพัฒนาปรับแต่งการเรียกฐานข้อมูลด้วยตนเอง บางคนเสนอให้รวมการดำเนินการฐานข้อมูลเข้าไปในตัวภาษาโปรแกรมโดยตรง

ปัญหา N+1 query เกิดขึ้นเมื่อแอปพลิเคชันส่งคำสั่งฐานข้อมูลหลายคำสั่งแยกกันแทนที่จะเป็นคำสั่งเดียวที่มีประสิทธิภาพ ตัวอย่างเช่น หากคุณต้องการข้อมูลของผู้ใช้ 100 คน แอปของคุณอาจส่งคำสั่ง 101 คำสั่ง (หนึ่งคำสั่งเพื่อดึงรายชื่อผู้ใช้ แล้วอีก 100 คำสั่งเพื่อดึงรายละเอียดของแต่ละคน) แทนที่จะเป็นเพียงสองคำสั่งที่ออกแบบมาอย่างดี

ตัวอย่างปัญหา N+1 Query:

  • วิธีที่ไม่ดี: 1 query เพื่อดึงรายชื่อผู้ใช้ + 100 queries เพื่อดึงรายละเอียดของผู้ใช้แต่ละคน = รวม 101 queries
  • วิธีที่ดี: 1 query เพื่อดึงรายชื่อผู้ใช้ + 1 query เพื่อดึงรายละเอียดผู้ใช้ทั้งหมด = รวม 2 queries
  • ผลกระทบต่อประสิทธิภาพ: อาจทำให้ประสิทธิภาพของฐานข้อมูลช้าลง 50 เท่าในแอปพลิเคชันจริง

การย้ายตรรกะฐานข้อมูลเข้าไปในตัวภาษาเอง

แนวคิดหลักที่กำลังถูกถกเถียงกันเกี่ยวข้องกับการทำให้การดำเนินการฐานข้อมูลเป็นส่วนหนึ่งที่ติดตั้งมาในตัวของภาษาโปรแกรม คล้ายกับวิธีที่ Haskell จัดการกับการปรับแต่งบางอย่าง สิ่งนี้จะช่วยให้คอมไพเลอร์ของภาษาตรวจจับและแก้ไขรูปแบบคำสั่งที่ไม่มีประสิทธิภาพโดยอัตโนมัติก่อนที่โค้ดจะทำงาน

สมาชิกในชุมชนชี้ให้เห็นว่าแนวทางนี้มีแบบอย่างมาก่อน ภาษาอย่าง C# มี LINQ to SQL อยู่แล้ว ซึ่งสามารถแปลงโค้ดปกติให้เป็นคำสั่งฐานข้อมูลที่ปรับแต่งแล้ว นักพัฒนาบางคนยังได้สร้างเครื่องมือที่สามารถนำฟังก์ชันโปรแกรมปกติมาแปลงให้เป็นโค้ด SQL โดยอัตโนมัติ

โซลูชันภาษาโปรแกรมมิ่งในปัจจุบัน:

  • C LINQ to SQL: แปลงนิพจน์โค้ด C ให้เป็นคำสั่ง SQL ที่ได้รับการปรับปรุงประสิทธิภาพ
  • Haskell rewrite rules: ให้ไลบรารีสามารถกำหนดรูปแบบการปรับปรุงประสิทธิภาพสำหรับคอมไพเลอร์
  • DelegateDecompiler: เครื่องมือที่แปลงฟังก์ชัน lambda ของ C ให้เป็นคำสั่งฐานข้อมูล
  • Django QuerySets: ORM ของ Python ที่ใช้ lazy evaluation เพื่อเปิดใช้งานการปรับปรุงประสิทธิภาพของคำสั่ง

ความท้าทายพื้นฐาน: ข้อมูลขณะทำงาน

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

ปัญหาพื้นฐานไม่ใช่แค่ว่าคอมไพเลอร์ของคุณไม่เข้าใจ SQL ปัญหาคือคอมไพเลอร์ของคุณไม่เข้าใจว่าข้อมูลถูกจัดเก็บหรือจะถูกจัดเก็บอย่างไร

ระบบฐานข้อมูลใช้ทรัพยากรมหาศาลในการสร้างสถิติและทำความเข้าใจรูปแบบข้อมูลเพื่อตัดสินใจปรับแต่งที่ดี ข้อมูลนี้เปลี่ยนแปลงอยู่ตลอดเวลาและไม่สามารถนำมาสร้างเข้าไปในภาษาโปรแกรมได้อย่างง่ายดาย

วิธีแก้ไขทางเลือกและแนวทางปฏิบัติ

แทนที่จะเปลี่ยนภาษา นักพัฒนาบางคนเสนอรูปแบบการออกแบบที่ดีกว่า แนวทางหนึ่งเกี่ยวข้องกับการส่งคืนออบเจ็กต์คำสั่งแบบ lazy-evaluated แทนผลลัพธ์ทันที สิ่งนี้ให้โอกาสโค้ดที่เรียกใช้ในการรวมการดำเนินการหลายอย่างให้เป็นการเรียกฐานข้อมูลเดียวที่มีประสิทธิภาพ

คนอื่นๆ สนับสนุนให้ละทิ้งเครื่องมือ Object-Relational Mapping (ORM) ที่ซับซ้อนทั้งหมด โดยโต้แย้งว่าชั้นนามธรรมของพวกมันทำให้การปรับแต่งเป็นไปไม่ได้เกือบจะเลย พวกเขาเสนอให้ใช้วิธีการเข้าถึงฐานข้อมูลที่ง่ายกว่าและตรงไปตรงมากว่า ซึ่งให้นักพัฒนาควบคุมการปรับแต่งคำสั่งได้อย่างเต็มที่

รูปแบบที่กว้างขึ้น

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

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

ชุมชนยังคงสำรวจวิธีแก้ไข ตั้งแต่การรวมระดับภาษาไปจนถึงการออกแบบ ORM ที่ดีกว่าหรือการละทิ้ง ORM ทั้งหมด แต่ละแนวทางมีประโยชน์และความท้าทายที่แตกต่างกัน สะท้อนถึงความซับซ้อนของการปรับแต่งประสิทธิภาพซอฟต์แวร์สมัยใหม่

อ้างอิง: Abstraction boundaries are optimization boundaries