ยังผิดไหมที่จะเริ่มต้นชื่อผู้ใช้ที่จัดเก็บโพรซีเดอร์ด้วย sp_?


33

หนึ่งในเพื่อนร่วมงานของฉันตั้งชื่อกระบวนงานที่เก็บไว้ในฐานข้อมูล SQL Server 2008 R2 ของsp_somethingเรา เมื่อฉันเห็นสิ่งนี้ฉันก็คิดทันที: "นั่นมันผิด!" และเริ่มค้นหาบุ๊กมาร์กของฉันสำหรับบทความออนไลน์นี้ซึ่งอธิบายว่าทำไมมันผิดดังนั้นฉันจึงสามารถให้คำอธิบายแก่เพื่อนร่วมงานของฉันได้

ในบทความ (โดยBrian Moran ) มีการอธิบายว่าการให้ขั้นตอนการจัดเก็บคำนำหน้าsp_ทำให้ SQL Server ดูที่ฐานข้อมูลหลักสำหรับแผนรวบรวม เนื่องจากsp_sprocไม่ได้อยู่ที่นั่น SQL Server จะคอมไพล์โพรเซสอีกครั้ง

ตัวอย่างต่อไปนี้ให้ไว้ในบทความเพื่อแสดงความแตกต่างระหว่างสองขั้นตอน:

USE tempdb;
GO

CREATE PROCEDURE dbo.Select1 AS SELECT 1;
GO

CREATE PROCEDURE dbo.sp_Select1 AS SELECT 1;
GO

EXEC dbo.sp_Select1;
GO

EXEC dbo.Select1;
GO

คุณรันสิ่งนี้จากนั้นเปิด Profiler (เพิ่มกระบวนงานที่เก็บไว้ -> SP:CacheMissเหตุการณ์) และเรียกใช้กระบวนงานที่เก็บไว้อีกครั้ง คุณควรจะเห็นความแตกต่างระหว่างสองกระบวนงานที่เก็บไว้: กระบวนงานที่sp_Select1เก็บไว้จะสร้างSP:CacheMissเหตุการณ์เพิ่มเติมมากกว่าหนึ่งSelect1กระบวนงานที่เก็บไว้ (บทความอ้างอิงSQL Server 7.0และSQL Server 2000 )

เมื่อฉันรันตัวอย่างในสภาพแวดล้อม SQL Server 2008 R2 ของฉันฉันจะได้รับSP:CacheMissเหตุการณ์จำนวนเท่ากันสำหรับทั้งสองโพรซีเดอร์ (ทั้งใน tempdb และในฐานข้อมูลทดสอบอื่น)

ดังนั้นฉันสงสัย:

  • ฉันสามารถทำสิ่งผิดพลาดในการดำเนินการตามตัวอย่างได้หรือไม่?
  • sproc sp_somethingadagium ' ไม่ตั้งชื่อผู้ใช้' ยังคงใช้ได้ใน SQL Server รุ่นที่ใหม่กว่าหรือไม่
  • ถ้าเป็นเช่นนั้นมีตัวอย่างที่ดีที่แสดงความถูกต้องใน SQL Server 2008 R2 หรือไม่

ขอบคุณมากสำหรับความคิดของคุณในเรื่องนี้!

แก้ไข

ฉันพบการสร้างกระบวนงานที่เก็บไว้ (โปรแกรมฐานข้อมูล)บน msdn สำหรับ SQL Server 2008 R2 ซึ่งตอบคำถามที่สองของฉัน:

เราขอแนะนำให้คุณไม่สร้างขั้นตอนการจัดเก็บใด ๆ โดยใช้ sp_ เป็นคำนำหน้า SQL Server ใช้คำนำหน้า sp_ เพื่อกำหนดขั้นตอนการจัดเก็บระบบ ชื่อที่คุณเลือกอาจขัดแย้งกับขั้นตอนของระบบในอนาคต [ ... ]

ไม่มีการกล่าวถึงสิ่งใดเกี่ยวกับปัญหาประสิทธิภาพที่เกิดจากการใช้ส่วนsp_นำหน้า ฉันชอบที่จะรู้ว่ายังคงเป็นกรณีหรือว่าพวกเขาแก้ไขมันหลังจาก SQL Server 2000


3
ฉันดูที่นี่มาก่อนและพบว่ามีความแตกต่างของประสิทธิภาพเล็กน้อยซึ่งฉันวางลงไปที่ค่าใช้จ่ายในการแก้ไขsp_เวอร์ชันที่สูงขึ้นเล็กน้อย(จำเป็นต้องตรวจสอบทั้งในฐานข้อมูลหลักและผู้ใช้เนื่องจากมันให้ความสำคัญกับระบบ procs ในmaster-> procs procs ในmaster)
Martin Smith

4
คุณเห็นประโยชน์อะไรบ้างสำหรับการเติมหน้าโพรซีเดอร์ที่เก็บไว้ด้วยsp_? นี้เป็นเรื่องเกี่ยวกับประโยชน์เท่า prefixing tblตารางที่มี เหตุใดจึงต้องทำให้ต้นแบบการค้นหาระบบเป็นอันดับแรก (แม้ว่าจะเล็กน้อยหรือไม่มีความแตกต่างด้านประสิทธิภาพ) เพื่อให้คุณสามารถใช้หลักการตั้งชื่อที่ไม่มีความหมายได้
Aaron Bertrand

1
@AaronBertrand: พูดตามตรงฉันไม่เห็นประโยชน์อะไรเลยในการเติม sprocs ด้วย sp_ ข้อเสียเท่านั้นและฉันจะไม่นำหน้าพวกเขาด้วยวิธีนี้เลย แต่ฉันต้องการข้อโต้แย้งทั้งหมดที่ฉันสามารถโน้มน้าวให้เพื่อนร่วมงานของฉันไม่ทำเช่นนั้น

1
ใช่ tbl ไร้ประโยชน์ แต่ฉันก็ยังชอบที่จะใช้มัน ต้องเป็น OCD ของฉันที่กำลังเข้ามาตอนนี้ลงจากสนามหญ้า
SQLRockstar

1
@Josien เช่นกันเพื่อนร่วมงานของคุณควรมาพร้อมกับข้อโต้แย้งเพื่อให้รูปแบบการตั้งชื่อมีความซับซ้อนมากขึ้น พวกเขาได้รับการอธิบายว่าทำไมดีกว่าdbo.sp_Author_Rename dbo.Author_Renameฉันไม่สามารถนึกถึงสิ่งเดียวที่สมเหตุสมผล
Aaron Bertrand

คำตอบ:


31

การทดสอบตัวเองค่อนข้างง่าย มาสร้างสองโพรซีเดอร์ง่ายๆกัน:

CREATE PROCEDURE dbo.sp_mystuff
AS
  SELECT 'x';
GO
CREATE PROCEDURE dbo.mystuff
AS
  SELECT 'x';
GO

ตอนนี้เรามาสร้าง wrapper ที่รันหลาย ๆ ครั้งโดยมีและไม่มีคำนำหน้าสคีมา:

CREATE PROCEDURE dbo.wrapper_sp1
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @i INT = 1;
    WHILE @i <= 1000
    BEGIN
      EXEC sp_mystuff;
      SET @i += 1;
    END
END
GO
CREATE PROCEDURE dbo.wrapper_1
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @i INT = 1;
    WHILE @i <= 1000
    BEGIN
      EXEC mystuff;
      SET @i += 1;
    END
END
GO
CREATE PROCEDURE dbo.wrapper_sp2
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @i INT = 1;
    WHILE @i <= 1000
    BEGIN
      EXEC dbo.sp_mystuff;
      SET @i += 1;
    END
END
GO
CREATE PROCEDURE dbo.wrapper_2
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @i INT = 1;
    WHILE @i <= 1000
    BEGIN
      EXEC dbo.mystuff;
      SET @i += 1;
    END
END
GO

ผล:

ป้อนคำอธิบายรูปภาพที่นี่

สรุป:

  • การใช้คำนำหน้า sp_ ช้ากว่า
  • การออกจากคำนำหน้าสคีมาช้ากว่า

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

นอกจากนี้ฉันทำการทดสอบรูปแบบนี้ในโพสต์บล็อกต่อไปนี้:

http://www.sqlperformance.com/2012/10/t-sql-queries/sp_prefix


หมายเหตุผลลัพธ์เหล่านี้อยู่ใน SQL Server 2012 แต่คุณสามารถทำการทดสอบเดียวกันในสภาพแวดล้อมของคุณ
แอรอนเบอร์ทรานด์ด์

1
"สิ่งที่ทำร่วมงานของคุณคาดหวังที่จะได้รับจากการทำเช่นนั้น" เห็นโน้ตฮังการี โดยทั่วไปมันเป็นสิ่ง 90s ส่วนใหญ่ นอกจากนี้ในงานที่ผ่านมาของฉันมาตรฐานคือการนำหน้าทุกขั้นตอนการจัดเก็บด้วยsp_เพื่อให้พวกเขาสามารถแตกต่างจากสิ่งอื่น ๆ และไม่มีความขัดแย้งชื่อ ... ฉันไม่คิดว่าปัญหาประสิทธิภาพการทำงานนี้มีอยู่กับมัน
Earlz

ตัวอย่างที่ดีขอบคุณแอรอน ฉันยังคงทดสอบมันในปี 2008 R2 (และอาจทดสอบในทางที่ผิดทำให้ 'dbo.wrapper_sp1' และ 'dbo.wrapper_sp2' ดูเร็วกว่าอีกสองคนในตอนนี้)

12

เราขอแนะนำให้คุณไม่สร้างขั้นตอนการจัดเก็บใด ๆ โดยใช้ sp_ เป็นคำนำหน้า SQL Server ใช้คำนำหน้า sp_ เพื่อกำหนดขั้นตอนการจัดเก็บระบบ ชื่อที่คุณเลือกอาจขัดแย้งกับขั้นตอนของระบบในอนาคต [ ... ]

ไม่มีสิ่งใดถูกกล่าวถึงเกี่ยวกับปัญหาประสิทธิภาพที่เกิดจากการใช้คำนำหน้า sp_ ฉันชอบที่จะรู้ว่ายังคงเป็นกรณีหรือว่าพวกเขาแก้ไขมันหลังจาก SQL Server 2000

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

และถ้ามันมีอยู่ระบบนั้นจะจัดเก็บขั้นตอนจาก masterฐานข้อมูลเสมอและจะถูกดำเนินการแทนตัวคุณ

ใช่แล้ว - มันยังคงอยู่: อย่าใช้ส่วนsp_นำหน้า


5
ทดสอบง่าย CREATE PROC dbo.sp_helptext AS SELECT 1จากนั้นลองEXEC dbo.sp_helptext
Martin Smith

ขอบคุณสำหรับคำตอบของคุณนอกจากนี้ยังมีประโยชน์อย่างมากสำหรับความชุกของmastersp

2

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

select * from Person.BusinessEntity b
inner join Person.BusinessEntityAddress ba on b.BusinessEntityID = ba.BusinessEntityID
inner join Person.Address a on ba.AddressID = a.AddressID

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

ข้อกังวลอีกประการหนึ่งคือเนื่องจาก procs "sp_" สามารถเรียกใช้งานจากต้นแบบได้คุณอาจได้รับสำเนาของ proc ที่ถูกเรียกใช้เป็น master แทนที่จะเป็น DB ที่คุณกำลังทำงานอยู่ แต่การทดสอบอย่างรวดเร็วจะแสดงว่าไม่ใช่กรณี อย่างไรก็ตามหาก proc หลุดจากฐานข้อมูลที่คุณกำลังทำงานอยู่และมีสำเนาอยู่ในต้นแบบแล้วมันจะถูกเรียกใช้งานซึ่งอาจเป็นปัญหาหากเป็นรุ่นเก่า หากนี่เป็นข้อกังวลฉันจะไม่ใช้ "sp_" เพื่อตั้งชื่อ proc


พบว่าน่าสนใจขอบคุณ! ฉันจะใช้ตัวอย่างของคุณร่วมกับตัวอย่างของ Aaronเพื่อทำการทดสอบเพิ่มเติม

1

ฉันเชื่อว่าปัญหาต้องทำเมื่อคุณไม่ได้ระบุชื่อวัตถุที่ผ่านการรับรองโดยสมบูรณ์ ดังนั้น "EXEC sp_something" จะตรวจสอบอาจารย์ก่อน แต่ "EXEC dbname.dbo.sp_something" จะไม่ไปเป็นผู้เชี่ยวชาญก่อน

บทเรียนถ้าฉันจำได้ก็คือใช้ชื่อที่ผ่านการรับรองโดยสมบูรณ์


5
อย่าคิดว่าจะสร้างความแตกต่าง EXEC MyDB.dbo.sp_helptext 'sp_helptext'ยังคงใช้จากmasterแม้ว่าจะมีหนึ่งในฐานข้อมูลผู้ใช้ AFAIK จะตรวจสอบสถานที่ทั้งสองและจะใช้จากmasterถ้ามีอยู่และถูกทำเครื่องหมายเป็นวัตถุระบบ
Martin Smith

1
@MartinSmith เมื่อวันที่ 2012 ฉันไม่สามารถบังคับรุ่นหลักที่จะดำเนินการ (แม้ว่าการทดสอบของฉันมีแสดงให้เห็นว่ามีบางสิ่งที่เกิดขึ้น) เว้นแต่ฉันจะคัดลอกสำเนาท้องถิ่น (ในกรณีที่MyDB.dbo.sp_fooยังคงดำเนินการรุ่นต้นแบบ) ฉันไม่มี 2008/2008 R2 ในตอนนี้เพื่อยืนยันว่าพฤติกรรมนี้เปลี่ยนไปหรือไม่
Aaron Bertrand

@AaronBertrand - โอ้น่าสนใจฉันทำการทดสอบของฉันใน 2008 R2
Martin Smith

นอกจากนี้โปรดทราบว่าหากไม่พบโพรซีเดอร์ในระบบและพบโพรเซสในต้นแบบโพรซีเดอร์จะถูกเรียกใช้และไม่จำเป็นต้องทำเครื่องหมายเป็นอ็อบเจ็กต์ระบบเพื่อให้สิ่งนี้เกิดขึ้น และในปี 2012 อย่างน้อยที่สุดไม่ว่าสำเนาต้นแบบจะถูกทำเครื่องหมายเป็นวัตถุของระบบหรือไม่ก็จะไม่เปลี่ยนพฤติกรรม - ไม่ว่าจะมีคำนำหน้า db / schema ในท้องถิ่นหรือไม่ก็ตามสำเนาภายในเครื่องจะถูกดำเนินการเสมอเว้นแต่จะไม่มีอยู่จริง
Aaron Bertrand

1
โอ๊ะฉันควรชี้แจงว่าความคิดเห็นของฉันมุ่งเน้นไปที่คำตอบที่แนะนำ ความคิดเห็นของ SQLRockstar "EXEC dbname.dbo.sp_something จะไม่มีทางไปถึงอันดับหนึ่งก่อน" ไม่ถูกต้อง
Greenstone Walker
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.