“ แบทช์” คืออะไรและเหตุใดจึงใช้ GO


135

ฉันได้อ่านและอ่าน MSDN แล้ว ฯลฯ ตกลงดังนั้นสัญญาณการสิ้นสุดของแบทช์

อะไรเป็นตัวกำหนดชุดงาน? ฉันไม่เห็นว่าทำไมฉันต้องไปเมื่อฉันวางสคริปต์หลาย ๆ สคริปต์เพื่อให้ทำงานพร้อมกัน

ฉันไม่เคยเข้าใจ GO ใครช่วยอธิบายได้ดีกว่านี้และฉันต้องใช้เมื่อไหร่ (หลังจากทำธุรกรรมกี่ครั้งหรือประเภทใด)

ตัวอย่างเช่นทำไมฉันต้อง GO หลังจากการอัปเดตแต่ละครั้งที่นี่:

 UPDATE [Country]
   SET [CountryCode] = 'IL'
 WHERE code = 'IL'

 GO

 UPDATE [Country]
   SET [CountryCode] = 'PT'
 WHERE code = 'PT'


FWIW ดูเหมือนว่าจะgoรีเซ็ต / ล้างdeclare @fooการประกาศตัวแปรด้วย - ฉันขอให้คุณต้องประกาศข้อผิดพลาด@fooจนกว่าฉันจะแสดงความคิดเห็นในไฟล์go.
JL Peyret

คำตอบ:


107

GOคือไม่ถูกต้องคำสั่ง TSQL

แทนที่จะเป็นคำสั่งไปยังโปรแกรมไคลเอนต์เฉพาะซึ่งเชื่อมต่อกับเซิร์ฟเวอร์ SQL (Sybase หรือของ Microsoft - ไม่แน่ใจเกี่ยวกับสิ่งที่ Oracle ทำ) ส่งสัญญาณไปยังโปรแกรมไคลเอ็นต์ว่าชุดคำสั่งที่ป้อนเข้ามาจนกว่าจะ "ไป" ต้องการ ที่จะส่งไปยังเซิร์ฟเวอร์เพื่อดำเนินการ

ทำไม / เมื่อไหร่ที่คุณต้องการ?

  • GO ในเซิร์ฟเวอร์ MS SQL มีพารามิเตอร์ "count" ดังนั้นคุณสามารถใช้เป็นทางลัด "ทำซ้ำ N ครั้ง" ได้

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

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

  • คำสั่ง SQL บางคำสั่งต้องคั่นด้วย GO จากคำสั่งต่อไปนี้เพื่อให้ทำงานได้

    ตัวอย่างเช่นคุณไม่สามารถวางตารางและสร้างตารางชื่อเดิมขึ้นมาใหม่ในธุรกรรมเดียวอย่างน้อยที่สุดใน Sybase (สำหรับการสร้างขั้นตอน / ทริกเกอร์):

> drop table tempdb.guest.x1          
> create table tempdb.guest.x1 (a int)
> go
  Msg 2714, Level 16, State 1
  Server 'SYBDEV', Line 2
  There is already an object named 'x1' in the database.   
  
> drop table tempdb.guest.x1          
> go
> create table tempdb.guest.x1 (a int)
> go
>

4
คำสั่ง GO ไม่สร้างธุรกรรม หากคุณรวมคำสั่ง GO หลายรายการไว้ในคำสั่ง BEGIN TRANSACTION เดียวและในท้ายที่สุดคุณจะทำ ROLLBACK มันจะย้อนกลับของ GO ทั้งหมด และถ้าในหนึ่ง GO อยู่ตรงกลางคุณจะได้รับข้อผิดพลาดบางอย่างและในท้ายที่สุดคุณจะทำการ COMMIT ทั้งหมด GO โดยไม่มีข้อผิดพลาดจะได้รับการยอมรับ เป็นเรื่องยุ่งยาก
TZ

7
GOไม่ "สร้างธุรกรรมให้คุณ" หากคุณไม่ได้ทำงานในธุรกรรมที่ชัดเจนแต่ละคำสั่งจะสร้างธุรกรรมของตัวเองอยู่ดี มันเป็นมุมฉากอย่างสมบูรณ์ หากคุณต้องการแยกการอัปเดตขนาดใหญ่ออกเป็นขั้นตอนเล็ก ๆ คุณยังสามารถทำได้ในชุดเดียวเหมือนในWHILE @@ROWCOUNT > 0รูปแบบทั่วไป
Martin Smith

3
ถ้าคุณไม่ได้ทำงานในการทำธุรกรรมอย่างชัดเจนแล้วUPDATE T1 SET X =2;UPDATE T1 SET X =2;จะทำงานเป็นสองรายการแยกต่างหากล่ะค่ะ การเพิ่มGOทำให้ไม่มีความแตกต่างอย่างแน่นอน และในทำนองเดียวกันถ้าคุณกำลังทำธุรกรรมอย่างชัดเจนมันจะครอบคลุมแบทช์และอีกครั้งก็GO ไม่แตกต่างกัน
Martin Smith

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

4
นอกจากนี้เนื่องจากข้อผิดพลาดบางอย่างจะยกเลิกชุดงาน (บางข้อผิดพลาดจะยกเลิกคำสั่งเท่านั้น) จึงมีบทบาทในการตรวจจับและกู้คืนข้อผิดพลาดด้วยเช่นกัน และข้อความบางอย่าง ( CREATE VIEWฯลฯ ) จำเป็นต้องอยู่ในชุดของตนเอง
Robert McKee

26

GO ไม่ใช่คำสั่ง แต่เป็นตัวคั่นชุดงาน

บล็อกที่คั่นด้วยGOไคลเอ็นต์จะส่งไปยังเซิร์ฟเวอร์เพื่อประมวลผลและไคลเอนต์รอผลลัพธ์

ตัวอย่างเช่นถ้าคุณเขียน

DELETE FROM a
DELETE FROM b
DELETE FROM c

สิ่งนี้จะถูกส่งไปยังเซิร์ฟเวอร์เป็น3แบบสอบถามบรรทัดเดียว

ถ้าคุณเขียน

DELETE FROM a
GO
DELETE FROM b
GO
DELETE FROM c

สิ่งนี้จะถูกส่งไปยังเซิร์ฟเวอร์เป็น3แบบสอบถามแบบบรรทัดเดียว

GOตัวเองไม่ไปที่เซิร์ฟเวอร์ (ไม่มีการเล่นสำนวน) มันเป็นฝั่งไคลเอ็นต์คำสงวนที่บริสุทธิ์และเป็นที่ยอมรับโดยเฉพาะและSSMSosql

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


4
ทำไมต้องแบทช์เลย ??
PositiveGuy

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

3
@coffeeaddict: โดยทั่วไปใช่ นอกจากนี้คำสั่งบางอย่างจำเป็นต้องมีก่อนในแบทช์ (เช่นCREATE SCHEMA); อื่น ๆ ต้องการเป็นข้อความเดียวในชุดของพวกเขา (เช่นSET SHOWPLAN_XML ON)
Quassnoi

19

คำสั่งจำนวนมากต้องอยู่ในชุดของตนเองเช่น CREATE PROCEDURE

หรือถ้าคุณเพิ่มคอลัมน์ลงในตารางก็ควรอยู่ในชุดของตัวเอง หากคุณพยายามเลือกคอลัมน์ใหม่ในชุดเดียวกันจะล้มเหลวเนื่องจากในเวลาแยกวิเคราะห์ / คอมไพล์ไม่มีคอลัมน์

GO ถูกใช้โดยเครื่องมือ SQL เพื่อทำงานนี้จากสคริปต์เดียว: ไม่ใช่คีย์เวิร์ด SQL และเอ็นจิ้นไม่รู้จัก

นี่คือ 2 ตัวอย่างที่เป็นรูปธรรมของการใช้แบทช์แบบวันต่อวัน

แก้ไข: ในตัวอย่างของคุณคุณไม่จำเป็นต้อง GO ...

แก้ไข 2 ตัวอย่าง คุณไม่สามารถวางสร้างและอนุญาตในชุดเดียวได้ ...

IF OBJECT_ID ('dbo.uspDoStuff') IS NOT NULL
    DROP PROCEDURE dbo.uspDoStuff
GO
CREATE PROCEDURE dbo.uspDoStuff
AS
SELECT Something From ATable
GO
GRANT EXECUTE ON dbo.uspDoStuff TO RoleSomeOne
GO

4

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

สมมติว่าคุณต้องการสร้างตารางทดสอบและโหลดด้วย 1,000 ระเบียน คุณสามารถออกคำสั่งต่อไปนี้และจะเรียกใช้คำสั่งเดียวกัน 1,000 ครั้ง:

CREATE TABLE dbo.TEST (ID INT IDENTITY (1,1), ROWID uniqueidentifier)
GO
INSERT INTO dbo.TEST (ROWID) VALUES (NEWID()) 
GO 1000

แหล่งที่มา: http://www.mssqltips.com/tip.asp?tip=1216

นอกเหนือจากนั้นจะทำเครื่องหมาย "สิ้นสุด" ของบล็อก SQL (เช่นในขั้นตอนการจัดเก็บ) ... หมายความว่าคุณอยู่ในสถานะ "สะอาด" อีกครั้ง ... eG: พารามิเตอร์ที่ใช้ในคำสั่งก่อนที่รหัสจะถูกรีเซ็ต ( ไม่ได้กำหนดอีกต่อไป)


โอเคแล้วทำไมคุณต้อง GO เพื่อให้คุณทราบว่าตารางถูกสร้างขึ้นก่อนที่จะเรียกใช้คำสั่งแทรก? ผมยังไม่เข้าใจ
PositiveGuy

ดูวิธีที่ฉันคิดเกี่ยวกับเรื่องนี้คือถ้าฉันไม่มี GO ในตัวอย่างของคุณตารางจะถูกสร้างขึ้นก่อนตอนนี้มันจะอยู่ที่นั่นดังนั้นส่วนแทรกควรจะทำงาน ฉันไม่เข้าใจว่า GO คืออะไรถ้าฉันสร้างตาราง ... มันมีให้สำหรับส่วนแทรกถัดไปไม่ใช่เหรอ!?!?!
PositiveGuy

2
@coffeeaddict: ไม่. "แบตช์" จะถูกแยกวิเคราะห์และรวบรวมในครั้งเดียว ในเวลาคอมไพล์ไม่มี dbo.TEST คุณไม่ได้สร้างอินสแตนซ์อ็อบเจ็กต์และ SQL ไม่ใช่โค้ดโพรซีเดอร์แบบบรรทัด
gbn

3

อย่างที่ทุกคนพูดไปแล้ว“ GO” ไม่ใช่ส่วนหนึ่งของ T-SQL "GO" คือตัวคั่นชุดงานใน SSMSซึ่งเป็นแอปพลิเคชันไคลเอนต์ที่ใช้ในการส่งแบบสอบถามไปยังฐานข้อมูล ซึ่งหมายความว่าตัวแปรที่ประกาศและตัวแปรตารางจะไม่คงอยู่จากโค้ดก่อน "GO" ไปจนถึงโค้ดที่ตามหลังมัน

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


1
มีประเด็นสำคัญที่ต้องทำที่นี่: คุณควรปฏิบัติต่อ GO ราวกับว่าเป็นคำหลักแม้ว่าจะไม่ใช่ คุณไม่ควรเปลี่ยนมัน ข้อบกพร่องที่เกิดจากการนำตัวระบุพิเศษกลับมาใช้ใหม่อาจเป็นเรื่องยากมากที่จะแก้ไขข้อบกพร่อง
Jørgen Fogh

@ The Dixie Flatline: คุณแน่ใจหรือว่าตัวแปรที่ประกาศไม่คงอยู่? ใน MSSQL 2016 ฉันได้รับข้อผิดพลาด "ตัวแปรที่ประกาศไว้แล้ว" เมื่อรัน: ประกาศ $ test int; ตั้ง $ test = 5; เลือก $ test go; ประกาศ $ test int; - แทนที่ $ ด้วย <at> ไม่สามารถใช้ <at> หลายรายการในความคิดเห็น SE
Wouter

0

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

แต่สามารถใช้เป็นคำสั่งเรียกซ้ำกับจำนวนเฉพาะ

ลอง:

exec sp_who2  
go 2

คำสั่งบางอย่างต้องถูกคั่นด้วย GO:

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