ฟังก์ชั่นประสิทธิภาพ


46

มาจากพื้นหลังของ MySQL ที่ประสิทธิภาพของขั้นตอนการจัดเก็บ(บทความเก่า)และการใช้งานเป็นที่น่าสงสัยฉันกำลังประเมิน PostgreSQL สำหรับผลิตภัณฑ์ใหม่สำหรับ บริษัท ของฉัน

หนึ่งในสิ่งที่ฉันอยากทำคือย้ายบางส่วนของตรรกะแอปพลิเคชันลงในกระบวนงานที่เก็บไว้ดังนั้นฉันจึงขอ DOs และ DON'Ts (แนวทางปฏิบัติที่ดีที่สุด) เกี่ยวกับการใช้ฟังก์ชันใน PostgreSQL (9.0) โดยเฉพาะเกี่ยวกับประสิทธิภาพการทำงานผิดพลาด


คุณหมายถึงคุณไม่ต้องการคำตอบพูดถึงสิ่งที่ไม่เกี่ยวข้องกับประสิทธิภาพหรือไม่?
แจ็คดักลาส

Chris Travers บล็อกมากมายเกี่ยวกับข้อดีของการใช้โพรซีเดอร์ที่เก็บไว้เช่นที่นี่: ledgersmbdev.blogspot.de/2012/07/…และที่นี่: ledgersmbdev.blogspot.de/2012/07/เพียงแค่อ่านผ่านบล็อกของเขา บทความน่าสนใจมากมายในหัวข้อนี้
a_horse_with_no_name

คำตอบ:


51

การพูดอย่างเคร่งครัดคำว่า "โพรซีเดอร์ที่เก็บไว้" ชี้ไปที่โพรซีเดอร์ SQLใน Postgres ซึ่งรู้จักกับ Postgres 11

นอกจากนี้ยังมีฟังก์ชั่นทำเกือบ แต่ไม่เหมือนกันและมีอยู่ตั้งแต่ต้น

ฟังก์ชั่นที่มีLANGUAGE sqlอยู่ที่พื้นเพียงไฟล์ชุดที่มีคำสั่ง SQL ธรรมดาในห่อฟังก์ชั่น (และดังนั้นจึงอะตอมเสมอทำงานภายในเดียวทำธุรกรรม) พารามิเตอร์การยอมรับ งบทั้งหมดในฟังก์ชั่น SQL มีการวางแผนในครั้งเดียวซึ่งแตกต่างอย่างละเอียดจากการดำเนินการหนึ่งคำสั่งหลังจากที่อื่นและอาจส่งผลกระทบต่อการสั่งซื้อที่ถูกล็อค

สำหรับสิ่งใด ๆ เพิ่มเติมภาษาที่เป็นผู้ใหญ่ที่สุดคือPL / pgSQL ( LANGUAGE plpgsql) มันทำงานได้ดีและได้รับการปรับปรุงทุกครั้งในช่วงทศวรรษที่ผ่านมา แต่มันทำหน้าที่ได้ดีที่สุดในฐานะกาวสำหรับคำสั่ง SQL มันไม่ได้มีไว้สำหรับการคำนวณหนัก (นอกเหนือจากคำสั่ง SQL)

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

นี้ดำเนินข้อดีและข้อเสียของการเตรียมงบ - ตามที่กล่าวไว้ในคู่มือ สำหรับการค้นหาบนตารางที่มีการกระจายข้อมูลที่ผิดปกติและพารามิเตอร์ที่แตกต่างกันแบบไดนามิก SQLด้วยEXECUTEอาจทำงานได้ดีขึ้นเมื่อได้รับจากแผนการดำเนินการที่ปรับให้เหมาะสมสำหรับพารามิเตอร์ที่กำหนดเมื่อเทียบกับค่าใช้จ่ายของการวางแผนใหม่

เนื่องจากแผนการดำเนินการทั่วไปของ Postgres 9.2 ยังคงถูกแคชไว้สำหรับเซสชัน แต่การอ้างอิงคู่มือ :

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

เราได้รับประโยชน์สูงสุดจากโลกทั้งสองโดยส่วนใหญ่ (มีค่าใช้จ่ายเพิ่มEXECUTEเล็กน้อย) โดยไม่ใช้ (ab) รายละเอียดมีอะไรใหม่ใน 9.2 PostgreSQLของ PostgreSQL วิกิพีเดีย

Postgres 12 แนะนำตัวแปรเซิร์ฟเวอร์plan_cache_modeเพิ่มเติมเพื่อบังคับแผนทั่วไปหรือกำหนดเอง สำหรับกรณีพิเศษใช้ด้วยความระมัดระวัง

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

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

ยกเว้นกฎนี้มีฟังก์ชั่น SQL ง่าย ( LANGUAGE sql) ซึ่งสามารถ"inlined" - ถ้าปัจจัยพื้นฐานบางส่วนจะได้พบกับ อ่านเพิ่มเติมเกี่ยวกับวิธีการทำงานของตัววางแผนคิวรีในงานนำเสนอนี้โดย Neil Conway (เนื้อหาขั้นสูง)

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

นั่นเป็นเหตุผลว่าทำไมฟังก์ชั่นจึงไม่ได้เป็น"ขั้นตอนการจัดเก็บ"อย่างแน่นอน(แม้ว่าบางครั้งจะมีการใช้คำศัพท์นั้นอาจทำให้เข้าใจผิด) คำสั่งบางคนชอบVACUUM, CREATE INDEX CONCURRENTLYหรือCREATE DATABASEไม่สามารถทำงานได้ภายในบล็อกธุรกรรมดังนั้นพวกเขาจะไม่ได้รับอนุญาตในการทำงาน (ทั้งในโพรซีเดอร์ SQL แต่ ณ Postgres 11 ซึ่งอาจถูกเพิ่มในภายหลัง)

ฉันเขียนฟังก์ชัน plpgsql หลายพันรายการในช่วงหลายปีที่ผ่านมา


2
@nhahtdh: "การทำธุรกรรมอัตโนมัติ" ไม่ใช่คำศัพท์ทางเทคนิค มันเป็นวิธีที่ไม่ค่อยสง่างามในการพูด .. สิ่งที่พูดตอนนี้หลังจากคำชี้แจงของฉัน ไม่ใช่ธุรกรรมที่เป็นอิสระเลย "autonomous" เพิ่งเกิดขึ้นเป็นคำที่คล้ายกัน
Erwin Brandstetter

4
คำตอบของคุณรวบรวมจากที่นี่และดังนั้นอาจเป็นคู่มือปฏิบัติที่ดีที่สุดของ PostGreSQL
Davos

10

บางส่วนของ:

  • ใช้ SQL เป็นภาษาฟังก์ชันเมื่อเป็นไปได้เนื่องจาก PG สามารถแทรกข้อความสั่งได้
  • ใช้ IMMUTABLE / STABLE / VOLATILE อย่างถูกต้องเนื่องจาก PG สามารถแคชผลลัพธ์หากไม่เปลี่ยนรูปหรือไม่เสถียร
  • ใช้ STRICT อย่างถูกต้องเนื่องจาก PG สามารถส่งคืน null ได้หากอินพุตใด ๆ เป็นโมฆะแทนที่จะเรียกใช้ฟังก์ชัน
  • พิจารณา PL / V8 เมื่อคุณไม่สามารถใช้ SQL เป็นภาษาฟังก์ชัน มันเร็วกว่า PL / pgSQL ในการทดสอบทางวิทยาศาสตร์บางอย่างที่ฉันวิ่ง
  • ใช้ LISTEN / NOTIFY สำหรับกระบวนการที่ใช้เวลานานซึ่งอาจเกิดขึ้นจากการทำธุรกรรม
  • พิจารณาการใช้ฟังก์ชั่นเพื่อใช้การแบ่งหน้าเนื่องจากการแบ่งหน้าตามคีย์สามารถเร็วกว่าการแบ่งหน้าตาม LIMIT
  • ตรวจสอบให้แน่ใจว่าคุณได้ทดสอบฟังก์ชั่นของคุณ

เป็นครั้งแรกที่ฉันเห็นการอ้างสิทธิ์ว่า PL / V8 เร็วกว่า PL / pgSQL คุณมีตัวเลข (ที่เผยแพร่) เพื่อสนับสนุนสิ่งนั้นหรือไม่?
a_horse_with_no_name

@a_horse_with_no_name ไม่ฉันไม่ อย่างที่ฉันพูดฉันทำการทดสอบตามหลักวิทยาศาสตร์ไม่กี่ครั้ง ส่วนใหญ่เป็นตรรกะไม่ใช่การเข้าถึงข้อมูล ฉันจะพยายามทำการทดสอบซ้ำ ๆ ในช่วงคริสต์มาสและโพสต์ใหม่ที่นี่
Neil McGuigan

@a_horse_with_no_name นี่เป็นตัวอย่างฉบับย่อสำหรับ FizzBuzz plv8 vs plpgsql: blog.databasepatterns.com/2014/08/plv8-vs-plpgsql.html
Neil McGuigan

8

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

ฉันเชื่อ (แต่ไม่แน่ใจ 100%) ว่าฟังก์ชั่นภาษา SQLนั้นเร็วกว่าฟังก์ชั่นอื่น ๆ ที่ใช้ภาษาอื่นเพราะพวกเขาไม่ต้องการสลับบริบท ข้อเสียคือไม่อนุญาตให้ใช้กระบวนการเชิงตรรกะ

PL / pgSQLเป็นภาษาที่มีการพัฒนาอย่างเต็มที่และสมบูรณ์ที่สุด แต่สำหรับประสิทธิภาพนั้นสามารถใช้Cได้ (แม้ว่าจะเป็นประโยชน์ต่อฟังก์ชันที่ต้องคำนวณอย่างเข้มข้นเท่านั้น)


7

คุณสามารถทำสิ่งที่น่าสนใจมากโดยใช้ฟังก์ชั่นที่ผู้ใช้กำหนด (UDF) ใน postgresql ตัวอย่างเช่นมีหลายภาษาที่เป็นไปได้ที่คุณสามารถใช้ได้ built ใน pl / sql และ pl / pgsql นั้นมีทั้งความสามารถและเชื่อถือได้และใช้วิธี sandbox เพื่อป้องกันไม่ให้ผู้ใช้ทำอะไรที่อันตรายเกินไป UDF ที่เขียนใน C ให้พลังงานและประสิทธิภาพขั้นสูงสุดแก่คุณเนื่องจากมันทำงานในบริบทเดียวกับฐานข้อมูล อย่างไรก็ตามมันก็เหมือนกับการเล่นด้วยไฟเพราะแม้แต่ความผิดพลาดเล็ก ๆ ก็อาจทำให้เกิดปัญหาใหญ่กับแบ็คเอนด์ที่ล้มเหลวหรือข้อมูลได้รับความเสียหาย ภาษา pl ของ custome เช่น pl / R, pl / ruby, pl / perl และอื่น ๆ ช่วยให้คุณสามารถเขียนทั้งฐานข้อมูลและเลเยอร์แอปในภาษาเดียวกัน สิ่งนี้มีประโยชน์เนื่องจากคุณไม่ต้องสอนโปรแกรมเมอร์ perl java หรือ pl / pgsql ฯลฯ เพื่อเขียน UDF

สุดท้ายมีภาษาpl / proxy ภาษา UDF นี้ช่วยให้คุณสามารถเรียกใช้แอปพลิเคชันของคุณในเซิร์ฟเวอร์ postgresql แบ็กเอนด์นับสิบหรือมากกว่าเพื่อการปรับขนาด ได้รับการพัฒนาโดยกลุ่มคนที่ดีของ Skype และโดยทั่วไปจะช่วยให้การแก้ปัญหาการปรับขนาดแนวนอนของคนยากจน มันง่ายที่จะเขียนด้วยเช่นกัน

ตอนนี้เป็นเรื่องของประสิทธิภาพ นี่คือพื้นที่สีเทา คุณกำลังเขียนแอพสำหรับคน ๆ หนึ่งหรือไม่? หรือ 1,000 หรือ 10,000,000? วิธีที่คุณสร้างแอปและใช้ UDF จะขึ้นอยู่กับว่าคุณพยายามปรับขนาดเป็นจำนวนมาก หากคุณกำลังเขียนให้กับผู้ใช้หลายพันคนแล้วสิ่งสำคัญที่คุณต้องทำคือลดภาระบนฐานข้อมูลให้มากที่สุด UDF ที่ลดจำนวนข้อมูลที่ถูกย้ายออกและกลับเข้าสู่ฐานข้อมูลจะช่วยลดการโหลด IO อย่างไรก็ตามหากพวกเขาเริ่มที่จะเพิ่มภาระของ CPU พวกเขาอาจจะมีปัญหา โดยทั่วไปการลดการโหลด IO เป็นสิ่งสำคัญอันดับแรกและตรวจสอบให้แน่ใจว่า UDF มีประสิทธิภาพเพื่อไม่ให้ CPU ของคุณทำงานหนักเกินไป

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