ฟังก์ชั่นเทียบกับขั้นตอนที่เก็บไว้


88

สมมติว่าฉันต้องใช้โค้ด T-SQL ที่ต้องส่งคืนตารางเป็นผลลัพธ์ ฉันสามารถใช้ฟังก์ชันค่าตารางหรืออื่น ๆ กระบวนงานที่เก็บไว้ที่ส่งคืนชุดของแถว ฉันควรใช้อะไร?

ในระยะสั้นสิ่งที่ฉันอยากรู้คือ:

ข้อแตกต่างหลักระหว่างฟังก์ชันและกระบวนงานที่จัดเก็บคืออะไร ฉันต้องคำนึงถึงอะไรบ้างในการใช้อย่างใดอย่างหนึ่ง


1
นี่น่าจะเป็นคำตอบที่สมบูรณ์แบบ: stackoverflow.com/a/1179778/365188
Ozair Kafray

คำตอบ:


51

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

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

ดังนั้นใช้ข้อใดก็ได้ที่ช่วยให้คุณสามารถแสดงผลลัพธ์ที่คุณต้องการได้


50

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

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

แต่มีประโยชน์อย่างแน่นอนสำหรับผลตอบแทนที่เป็นมูลค่าตารางในกรณีที่เฉพาะเจาะจงมาก

หากคุณต้องการแยกวิเคราะห์รายการที่คั่นด้วยจุลภาคเพื่อจำลองการส่งอาร์เรย์ไปยังโพรซีเดอร์ฟังก์ชันสามารถเปลี่ยนรายการให้เป็นตารางสำหรับคุณได้ นี่เป็นวิธีปฏิบัติทั่วไปสำหรับ Sql Server 2005 เนื่องจากเราไม่สามารถส่งผ่านตารางไปยังโพรซีเดอร์ที่จัดเก็บได้ (เราทำได้ในปี 2008)


1
แต่คุณสามารถส่ง XML ไปยังขั้นตอนการจัดเก็บ: stackoverflow.com/questions/144550/…
cllpse

2
ผิดฟังก์ชันเซิร์ฟเวอร์ SQL ส่วนใหญ่ไม่ถูกกำหนดเช่น getdate ในเซิร์ฟเวอร์ MS-SQL เฉพาะฟังก์ชัน ODBC เท่านั้นที่เป็นฟังก์ชันมาตรฐาน (= เร็วกว่ามาก + สามารถจัดทำดัชนีได้) ... แต่คุณถูกต้องมากควร จำกัด การใช้ฟังก์ชันในแบบสอบถามให้มากที่สุดเท่าที่จะทำได้ด้วยเหตุผลด้านประสิทธิภาพ
Stefan Steiger

45

จากเอกสาร :

หากกระบวนงานที่จัดเก็บตรงตามเกณฑ์ต่อไปนี้เป็นตัวเลือกที่ดีสำหรับการเขียนใหม่เป็นฟังก์ชันที่มีมูลค่าตาราง:

  • ตรรกะสามารถแสดงออกได้ในคำสั่ง SELECT เดียว แต่เป็นกระบวนงานที่เก็บไว้แทนที่จะเป็นมุมมองเพียงเพราะความต้องการพารามิเตอร์

  • กระบวนงานที่เก็บไว้ไม่ดำเนินการอัพเดตยกเว้นตัวแปรตาราง

  • ไม่จำเป็นต้องมีข้อความสั่งการดำเนินการแบบไดนามิก

  • กระบวนงานที่เก็บไว้จะส่งคืนชุดผลลัพธ์หนึ่งชุด

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


12

ฉันจะเขียนความแตกต่างที่น่าสนใจเล็กน้อยระหว่างขั้นตอนและฟังก์ชันที่จัดเก็บไว้

  • เราสามารถใช้ฟังก์ชันในคิวรีแบบเลือกได้ แต่เราไม่สามารถใช้โพรซีเดอร์ที่เก็บไว้ในคิวรีที่เลือกได้
  • เราไม่สามารถใช้ฟังก์ชันที่ไม่ได้กำหนดในฟังก์ชัน แต่เราสามารถใช้ฟังก์ชันที่ไม่ใช่ปัจจัยกำหนดในกระบวนงานที่เก็บไว้ ตอนนี้มีคำถามขึ้นมาว่าอะไรคือฟังก์ชันที่ไม่ใช่ดีเทอร์มินิสติก .. Ans คือ: -

    ฟังก์ชันที่ไม่กำหนดคือฟังก์ชันที่ส่งคืนเอาต์พุตที่แตกต่างกันสำหรับค่าอินพุตเดียวกันในเวลาที่ต่างกันเช่น getdate () มันจะคืนค่าที่แตกต่างกันเสมอทุกครั้งที่มีการเรียกใช้

    ข้อยกเว้น: -

    เซิร์ฟเวอร์ sql เวอร์ชันก่อนหน้าก่อน sql 2000 ไม่อนุญาตให้ใช้ฟังก์ชัน getdate () ในฟังก์ชันที่ผู้ใช้กำหนด แต่เวอร์ชัน 2005 เป็นต้นไปอนุญาตให้เราใช้ฟังก์ชัน getdate () ภายในฟังก์ชันที่ผู้ใช้กำหนด

    Newid () เป็นอีกตัวอย่างหนึ่งของฟังก์ชันที่ไม่ได้กำหนด แต่ไม่สามารถใช้ในฟังก์ชันที่ผู้ใช้กำหนดเองได้ แต่เราสามารถใช้ในกระบวนงานที่เก็บ

  • เราสามารถใช้คำสั่ง DML (แทรกอัปเดตลบ) ภายในกระบวนงานที่จัดเก็บ แต่เราไม่สามารถใช้คำสั่ง DML ในฟังก์ชันบนตารางจริงหรือตารางถาวรได้ หากเราต้องการดำเนินการ DML ในฟังก์ชันเราสามารถทำได้โดยใช้ตัวแปรตารางที่ไม่ใช่ตารางถาวร

  • เราไม่สามารถใช้การจัดการข้อผิดพลาดภายในฟังก์ชัน แต่เราสามารถจัดการข้อผิดพลาดในกระบวนงานที่จัดเก็บไว้ได้


การทำงานของ DML ได้รับการสนับสนุนในฟังก์ชัน MySQL อย่างไร
Joey Pinto

@JoeyPinto. เนื่องจาก myNONsql ไม่ใช่การร้องเรียน SQL แน่นอนว่ามันมีความพิเศษ แต่ไม่ใช่พื้นฐาน
PerformanceDBA

8
  1. ขั้นตอนสามารถส่งคืนค่าศูนย์หรือ n ในขณะที่ฟังก์ชันสามารถส่งคืนค่าหนึ่งซึ่งจำเป็น

  2. โพรซีเดอร์สามารถมีพารามิเตอร์อินพุต / เอาต์พุตได้ในขณะที่ฟังก์ชันสามารถมีได้เฉพาะพารามิเตอร์อินพุตเท่านั้น

  3. ขั้นตอนอนุญาตให้เลือกเช่นเดียวกับคำสั่ง DML ในขณะที่ฟังก์ชันอนุญาตให้เลือกคำสั่งในนั้นเท่านั้น

  4. ฟังก์ชันสามารถเรียกใช้จากโพรซีเดอร์ในขณะที่โพรซีเดอร์ไม่สามารถเรียกใช้จากฟังก์ชันได้

  5. ข้อยกเว้นสามารถจัดการได้โดย try-catch block ในขั้นตอนในขณะที่ try-catch block ไม่สามารถใช้ในฟังก์ชันได้

  6. เราสามารถไปจัดการธุรกรรมตามขั้นตอนในขณะที่เราไม่สามารถเข้าไปในฟังก์ชันได้

  7. ไม่สามารถใช้โพรซีเดอร์ในคำสั่ง select ได้ในขณะที่ฟังก์ชันสามารถฝังอยู่ในคำสั่ง select ได้

  8. สามารถใช้ UDF (ฟังก์ชันที่กำหนดโดยผู้ใช้) ในคำสั่ง SQL ที่ใดก็ได้ในส่วนWHERE/ HAVING/ SELECTในขณะที่ไม่สามารถเก็บโพรซีเดอร์ได้

  9. UDF ที่ส่งคืนตารางสามารถถือว่าเป็นชุดแถวอื่น สามารถใช้ในJOINs กับตารางอื่น ๆ

  10. UDF แบบอินไลน์อาจเป็นได้ว่าเป็นมุมมองที่รับพารามิเตอร์และสามารถใช้ในJOINการดำเนินการ s และ rowset อื่น ๆ


6

หากคุณมีฟังก์ชันคุณสามารถใช้เป็นส่วนหนึ่งของคำสั่ง SQL ของคุณได้เช่น

SELECT function_name(field1) FROM table

วิธีนี้ใช้ไม่ได้กับโพรซีเดอร์ที่เก็บไว้


1
ฉันคิดว่าเขากำลังพูดถึงฟังก์ชันที่ส่งคืนค่าตาราง
wcm

1
ฉันกำลังพูดถึงเรื่องทั่วไป แต่สำหรับกรณีเฉพาะของฉันตอนนี้ฉันอยู่ระหว่างขั้นตอนการจัดเก็บหรือฟังก์ชันที่มีมูลค่าตาราง
Auron

5

ฉันทำการทดสอบด้วยบิตตรรกะที่ใช้งานได้ยาวนานโดยมีรหัสบิตเดียวกัน (คำสั่ง SELECT แบบยาว) ที่ทำงานทั้งใน Table Valued Function และ Stored Procedure และการดำเนินการแบบตรง / SELECT และแต่ละรายการดำเนินการเหมือนกัน

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

CREATE FUNCTION dbo.getSitePermissions(@RegionID int, @optPersonID int, optSiteID int)
AS
RETURN 
    SELECT DISTINCT SiteID, PersonID
    FROM dbo.SiteViewPermissions
    WHERE (@optPersonID IS NULL OR @optPersonID = PersonID)
    AND (@optSiteID IS NULL OR @optSiteID = SiteID)
    AND @RegionID = RegionID

ด้วยวิธีนี้คุณสามารถใช้ฟังก์ชันนี้กับสถานการณ์ต่างๆได้มากมายและไม่ต้องใช้ประสิทธิภาพสูง ฉันเชื่อว่าสิ่งนี้มีประสิทธิภาพมากกว่าการกรองในภายหลัง:

SELECT * FROM dbo.getSitePermissions(@RegionID) WHERE SiteID = 1

ฉันใช้เทคนิคนี้ในหลายฟังก์ชันบางครั้งมีรายการพารามิเตอร์ "ทางเลือก" ประเภทนี้เป็นจำนวนมาก


4

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

ถ้าฉันต้องการส่งคืนชุดระเบียนหลายชุดหรือหากมีการอัปเดตค่าในตารางฉันจะใช้กระบวนงานที่เก็บไว้

2 เซ็นต์ของฉัน


4

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

SELECT *
FROM dbo.tvfVeryLargeResultset1(@myVar1) tvf1
INNER JOIN dbo.tvfVeryLargeResultset1(@myVar2) tvf2
    ON (tvf1.JoinId = tvf2.JoinId)

บ่อยครั้งคุณต้องยอมรับความซ้ำซ้อนของโค้ดที่ tvf สามารถกำจัดได้ (ด้วยต้นทุนประสิทธิภาพที่ยอมรับไม่ได้)

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


1

ฉันจะทดสอบทั้งสองอย่าง เป็นไปได้ว่าวิธี sp หรือตารางที่ได้มาจะเร็วกว่าฟังก์ชันอย่างมีนัยสำคัญและควรใช้แนวทางนั้น โดยทั่วไปฉันหลีกเลี่ยงฟังก์ชั่นเนื่องจากอาจเป็นหมูที่มีประสิทธิภาพ


1

ขึ้นอยู่กับ :) หากคุณต้องการใช้ผลลัพธ์ที่เป็นตารางในขั้นตอนอื่นคุณควรใช้ฟังก์ชัน TableValued มากกว่า หากผลลัพธ์เป็นของไคลเอนต์ proc ที่จัดเก็บไว้จะเป็นวิธีที่ดีกว่า


-1

โพรซีเดอร์ที่จัดเก็บไว้เป็นแบบสอบถามที่รวบรวมไว้ล่วงหน้าซึ่งดำเนินการได้เร็วขึ้นและบันทึกจากการฉีด sql สามารถคืนค่า 0 หรือ N เราสามารถดำเนินการ DML ภายในโพรซีเดอร์ที่จัดเก็บไว้ เราสามารถใช้ฟังก์ชันภายในโพรซีเดอร์และสามารถใช้ฟังก์ชันในคิวรีแบบเลือกได้ ฟังก์ชันใช้เพื่อส่งคืนค่าใด ๆ และการดำเนินการ DML ไม่สามารถทำได้ในฟังก์ชัน ฟังก์ชันมีสองประเภทสเกลาร์และค่า tabled ฟังก์ชันสเกลาร์ส่งคืนค่าเดียวฟังก์ชันค่า tabled ที่ใช้ในการส่งคืนแถวของตาราง


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