มันเป็นการปฏิบัติที่ไม่ถูกต้องหรือไม่ที่จะสร้างธุรกรรมอยู่เสมอ?


88

มันเป็นการปฏิบัติที่ไม่ถูกต้องหรือไม่ที่จะสร้างธุรกรรมอยู่เสมอ?

ยกตัวอย่างเช่นมันเป็นวิธีที่ดีในการสร้างการทำธุรกรรมเพื่ออะไร แต่คนที่เรียบง่ายSELECT?

ต้นทุนในการสร้างธุรกรรมเมื่อไม่จำเป็นจริงๆคืออะไร?

แม้ว่าคุณจะใช้ระดับการแยกเช่นREAD UNCOMMITTEDนั้นมันเป็นการปฏิบัติที่ไม่ดีหรือไม่?


1
การดูผลกระทบของBEGIN TRAN SELECT ... COMMITvs SELECTดูเหมือนจะมีความแตกต่างของประสิทธิภาพเล็กน้อยมาก
Martin Smith

คำตอบ:


100

การปฏิบัติที่ไม่ดีในการสร้างธุรกรรมอยู่เสมอหรือไม่?

ขึ้นอยู่กับบริบทที่คุณกำลังพูดอยู่ที่นี่ หากเป็นการอัพเดทฉันขอแนะนำอย่างยิ่งให้ใช้ธุรกรรมอย่างชัดเจน ถ้ามันเป็น SELECT แล้วไม่ใช่ (อย่างชัดเจน)

แต่เดี๋ยวก่อนมีสิ่งที่ต้องทำความเข้าใจเพิ่มเติมก่อน: ทุกอย่างในเซิร์ฟเวอร์ sql มีอยู่ในธุรกรรม

เมื่อตัวเลือกเซสชั่นIMPLICIT_TRANSACTIONSเป็นOFFและคุณระบุอย่างชัดเจนbegin tranและcommit/rollbackแล้วนี้เป็นที่รู้จักกันทั่วไปว่าเป็นรายการที่เกี่ยวโยงกันชัดเจน มิฉะนั้นคุณจะได้รับการทำธุรกรรมอัตโนมัติ

เมื่อ IMPLICIT_TRANSACTIONSใดที่ONการทำธุรกรรมโดยนัยจะเริ่มโดยอัตโนมัติเมื่อดำเนินการหนึ่งในประเภทข้อความสั่งที่ระบุไว้ในบทความหนังสือออนไลน์ (เช่นSELECT/ UPDATE/ CREATE) และจะต้องกระทำหรือย้อนกลับอย่างชัดเจน การดำเนินการBEGIN TRANในโหมดนี้จะเป็นการเพิ่ม@@TRANCOUNTและเริ่มทำธุรกรรม "ซ้อน" อีกรายการหนึ่ง)

หากต้องการสลับโหมดที่คุณอยู่คุณจะต้องใช้

SET IMPLICIT_TRANSACTIONS ON

หรือ

SET IMPLICIT_TRANSACTIONS OFF

select @@OPTIONS & 2

ถ้าข้างต้นกลับ 2 คุณอยู่ในโหมดการทำธุรกรรมโดยปริยาย ถ้ามันคืนค่า 0 แสดงว่าคุณกำลังอยู่ในระบบบันทึกอัตโนมัติ

ราคาเท่าไหร่ในการสร้างธุรกรรมเมื่อไม่จำเป็นจริงๆ?

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

แม้ว่าคุณจะใช้ระดับการแยก read_uncomitted เป็นการปฏิบัติที่ไม่ดีหรือไม่? เพราะมันไม่ควรมีปัญหากับการล็อค

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

คุณสามารถใช้สิ่งนี้ในระดับการเชื่อมต่อ / แบบสอบถามเพื่อที่จะไม่ส่งผลกระทบต่อแบบสอบถามอื่น ๆ

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

พบบทความที่น่าสนใจโดย Jeff Atwood อธิบาย Deadlocks เนื่องจาก Puzzle Philosophers Dining และอธิบายการ อ่านระดับสแนปช็อตระดับความมุ่งมั่น

แก้ไข:

จากความอยากรู้ฉันได้ทำการทดสอบการวัดผลกระทบของ T-log ด้วยเคาน์เตอร์ Perfmon เช่น Log Bytes Flushed / Sec, Log Flush Waits / Sec (จำนวนคอมมิทต่อวินาทีที่รอ LOG flush เกิดขึ้น) ดังกราฟด้านล่าง:

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

รหัสตัวอย่าง:

create table testTran (id int, Name varchar(8))
go

-- 19 sec
-- Autocommit transaction
declare @i int
set @i = 0
while @i < 100000
begin 
insert into testTran values (1,'Kin Shah')
set @i = @i+1
end
---------------------------------------------------
-- 2 sec
-- Implicit transaction
SET IMPLICIT_TRANSACTIONS ON
declare @i int
set @i = 0
while @i < 100000
begin 
insert into testTran values (1,'Kin Shah')
set @i = @i+1
end
COMMIT;
SET IMPLICIT_TRANSACTIONS OFF


----------------------------------------------------
-- 2 sec
-- Explicit transaction
declare @i int
set @i = 0
BEGIN TRAN
WHILE @i < 100000
Begin
INSERT INTO testTran values (1,'Kin Shah')
set @i = @i+1
End
COMMIT TRAN

ธุรกรรม Autocommit : (แก้ไขตามที่เน้นโดย @TravisGan)

  • ส่วนแทรกใช้เวลา 19 วินาที
  • Autocommit ทุกตัวจะล้างบัฟเฟอร์ T-log ไปยังดิสก์เนื่องจาก autocomit (หลังจาก @TravisGan ถูกเน้นและฉันพลาดมันไป)
  • กระบวนการ CHECKPOINT จะเสร็จสิ้นอย่างรวดเร็วเนื่องจากจำนวนบัฟเฟอร์บันทึกสกปรกที่ต้องใช้ในการล้างข้อมูลจะน้อยลงเมื่อทำงานเงียบบ่อย

ผลกระทบและการทำธุรกรรมที่ชัดเจน:

  • ส่วนแทรกใช้เวลา 2 วินาที
  • สำหรับธุรกรรมที่ชัดเจนบัฟเฟอร์การบันทึกจะถูกล้างออกเมื่อเต็มแล้วเท่านั้น
  • ตรงกันข้ามกับธุรกรรม Autocommit ในธุรกรรม EXPLICIT กระบวนการ CHECKPOINT จะใช้เวลานานขึ้นเนื่องจากจะมีบัฟเฟอร์บันทึกเพิ่มเติมให้ล้างออก (จำไว้ว่าบัฟเฟอร์บันทึกจะถูกล้างข้อมูลเมื่อเต็มเท่านั้น)

มี DMV sys.dm_tran_database_transactionsที่จะส่งคืนข้อมูลเกี่ยวกับธุรกรรมที่ระดับฐานข้อมูล

เห็นได้ชัดว่านี่เป็นการทดสอบแบบง่าย ๆ เพื่อแสดงผลกระทบ ปัจจัยอื่น ๆ เช่นระบบย่อยของดิสก์การตั้งค่าการเติบโตอัตโนมัติของฐานข้อมูลขนาดเริ่มต้นของฐานข้อมูลกระบวนการอื่น ๆ ที่ทำงานบนเซิร์ฟเวอร์ \ ฐานข้อมูลเดียวกัน ฯลฯ จะมีผลเช่นกัน

จากการทดสอบข้างต้นไม่มีความแตกต่างระหว่างธุรกรรมโดยนัยและโดยนัย

ขอบคุณ @TravisGan ที่ช่วยเพิ่มคำตอบให้มากขึ้น


35

คำสั่ง SQL จะทำงานในธุรกรรมเสมอ หากคุณไม่ได้เริ่มต้นอย่างชัดเจนทุกคำสั่ง SQL จะทำงานในการทำธุรกรรมของตัวเอง

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


1

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

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