การปฏิบัติที่ไม่ดีในการสร้างธุรกรรมอยู่เสมอหรือไม่?
ขึ้นอยู่กับบริบทที่คุณกำลังพูดอยู่ที่นี่ หากเป็นการอัพเดทฉันขอแนะนำอย่างยิ่งให้ใช้ธุรกรรมอย่างชัดเจน ถ้ามันเป็น 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 ที่ช่วยเพิ่มคำตอบให้มากขึ้น
BEGIN TRAN SELECT ... COMMIT
vsSELECT
ดูเหมือนจะมีความแตกต่างของประสิทธิภาพเล็กน้อยมาก