ROLLBACK ใช้งานได้รวดเร็วหรือไม่


20

เป็นความจริงหรือไม่ที่ระบบ RDBMS นั้นได้รับการปรับให้เหมาะสมสำหรับCOMMITการทำงาน? การดำเนินการช้าลง / เร็วเท่าไหร่ROLLBACKและทำไม

คำตอบ:


14

สำหรับ SQL Server คุณสามารถยืนยันว่าการดำเนินการกระทำไม่มีอะไรมากไปกว่าการเขียน LOP_COMMIT_XACT ไปยังล็อกไฟล์และปล่อยการล็อกซึ่งแน่นอนว่าจะเร็วกว่า ROLLBACK ของการดำเนินการทุกธุรกรรมของคุณตั้งแต่ BEGIN TRAN

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

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

แก้ไข: มันขึ้นอยู่กับบิต ...

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

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

แก้ไข 2: จากการอภิปรายในความคิดเห็นต่อไปนี้เป็นตัวอย่างที่วางแผนไว้มากเพื่อแสดงให้เห็นว่างานที่ทำเป็นปัจจัยสำคัญในการกำหนดค่าใช้จ่ายสัมพัทธ์ของการกระทำ vs ย้อนกลับเป็นการดำเนินการ

สร้างสองตารางและแพ็คอย่างไม่มีประสิทธิภาพ (พื้นที่ว่างเปล่าต่อหน้า):

SET STATISTICS IO OFF;
SET STATISTICS TIME OFF;
SET NOCOUNT ON;
GO

CREATE TABLE dbo.Foo
(
    col1 INT IDENTITY(1,1) PRIMARY KEY CLUSTERED
    , col2 CHAR(4000) NOT NULL DEFAULT REPLICATE('A', 4000)
)

CREATE TABLE dbo.Bar
(
    col1 INT IDENTITY(1,1) PRIMARY KEY CLUSTERED
    , col2 CHAR(4000) NOT NULL DEFAULT REPLICATE('A', 4000)
)
GO

INSERT dbo.Foo DEFAULT VALUES
GO 100000

INSERT dbo.Bar DEFAULT VALUES
GO 100000

เรียกใช้คิวรีการอัปเดต "ไม่ดี" การวัดเวลาที่ใช้ในการทำงานและเวลาที่ใช้ในการออกคำสั่ง

DECLARE 
    @StartTime DATETIME2
    , @Rows INT

SET @Rows = 1

CHECKPOINT
DBCC DROPCLEANBUFFERS

BEGIN TRANSACTION

SET @StartTime = SYSDATETIME()

UPDATE
    dbo.bar
SET
    col2 = REPLICATE('B', 4000)
FROM
    dbo.bar b
INNER JOIN
    (
    SELECT TOP(@Rows)
        col1
    FROM
        dbo.foo
    ORDER BY
        NEWID()
    ) f
ON  f.col1 = b.col1
OPTION (MAXDOP 1)

SELECT 'Find and update row', DATEDIFF(ms, @StartTime, SYSDATETIME())

SET @StartTime = SYSDATETIME()

COMMIT TRANSACTION

SELECT 'Commit', DATEDIFF(ms, @StartTime, SYSDATETIME())
GO

ทำเช่นเดียวกันอีกครั้ง แต่ออกและวัดการย้อนกลับ

    DECLARE 
    @StartTime DATETIME2
    , @Rows INT

SET @Rows = 1

CHECKPOINT
DBCC DROPCLEANBUFFERS

BEGIN TRANSACTION

SET @StartTime = SYSDATETIME()

UPDATE
    dbo.bar
SET
    col2 = REPLICATE('B', 4000)
FROM
    dbo.bar b
INNER JOIN
    (
    SELECT TOP(@Rows)
        col1
    FROM
        dbo.foo
    ORDER BY
        NEWID()
    ) f
ON  f.col1 = b.col1
OPTION (MAXDOP 1)

SELECT 'Find and update row', DATEDIFF(ms, @StartTime, SYSDATETIME())

SET @StartTime = SYSDATETIME()

ROLLBACK TRANSACTION

SELECT 'Rollback', DATEDIFF(ms, @StartTime, SYSDATETIME())
GO

ด้วย @ Rows = 1 ฉันมีเหตุผลที่สอดคล้องกัน:

  • 5500ms สำหรับการค้นหา / อัปเดต
  • กระทำ 3ms
  • ย้อนกลับ 1ms

ด้วย @ Rows = 100:

  • 8500ms ค้นหา / อัปเดต
  • กระทำ 15ms
  • ย้อนกลับ 15ms

ด้วย @ Rows = 1,000:

  • 15000ms ค้นหา / อัปเดต
  • กระทำ 10ms
  • ย้อนกลับ 500ms

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


2
'งานน้อยลง' ไม่จำเป็นต้อง 'เร็วขึ้น'
แจ็คดักลาส

ฉันรู้ว่าbegin tranเพียงเพิ่มเคาน์เตอร์การทำธุรกรรม หากฉันเข้าใจคุณ rdbms กำลังทำงานทั้งหมด (รวมแถวสร้างแผนการดำเนินการ ... ) ที่ COMMIT ใช่หรือไม่
garik

3
ไม่งานทุกอย่างเสร็จสิ้นก่อนส่งมอบ การดำเนินการกระทำตัวเองค่อนข้างน้อย
Mark Storey-Smith

@ Mark ฉันได้ทำการทดสอบอย่างคร่าวๆและพร้อมแล้วที่จะแทรกแถว 2m และคอมมิชชันหรือย้อนกลับ เวลาโดยรวมรวมถึงการย้อนกลับมีตั้งแต่ 10 ถึง 30 วินาทีเมื่อเทียบกับ 6s และ 14s สำหรับเวลาโดยรวมรวมถึงการส่ง YMMV แน่นอน แต่สิ่งนี้บ่งชี้ว่าการย้อนกลับของ ballpark เกือบจะนานหรือนานกว่านั้นที่การทำธุรกรรมดั้งเดิมอย่างน้อยก็ในสภาพแวดล้อมของฉัน
แจ็คดักลาส

2
หากคุณต้องวัดเวลาสำหรับการดำเนินการส่งข้อมูลให้เสร็จสมบูรณ์ฉันคาดหวังว่ามันจะน้อยที่สุดเว้นแต่จะมีจุดตรวจสอบเกิดขึ้นในเวลาเดียวกัน (ซึ่งแยกจากกันและไม่เกี่ยวข้อง) นั่นคือประเด็นของฉันความมุ่งมั่นทำน้อยมากในขณะที่การย้อนกลับทำทุกอย่างที่เกิดขึ้นก่อนการกระทำบวกอีกเล็กน้อย ความแปรปรวนในการทดสอบของคุณเป็นปัจจัยอื่นที่ดีที่สุดในการเล่น แต่แน่นอนว่าฉันจะพยายามและรวบรวมสคริปต์บางอย่างเข้าด้วยกันในภายหลัง
Mark Storey-Smith

13

สำหรับ Oracle การย้อนกลับอาจใช้เวลานานกว่าเวลาที่ใช้ในการทำการเปลี่ยนแปลงที่จะย้อนกลับ สิ่งนี้มักไม่สำคัญเพราะ

  1. ไม่มีการล็อกในขณะที่ธุรกรรมกำลังย้อนกลับ
  2. มันถูกจัดการโดยกระบวนการพื้นหลังที่มีลำดับความสำคัญต่ำ

สำหรับ SQL Server ฉันไม่แน่ใจว่าสถานการณ์เหมือนกัน แต่จะมีคนอื่นบอกว่าไม่ใช่ ...

สำหรับ "ทำไม" ฉันจะบอกว่าrollbackควรจะหายากโดยปกติแล้วก็ต่อเมื่อมีอะไรผิดพลาดและแน่นอนว่าcommitมีแนวโน้มที่จะเป็นเรื่องธรรมดามากขึ้น - ดังนั้นจึงเหมาะสมที่จะปรับcommit


9

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

ทั้งหมดนี้เปลี่ยนแปลงด้วย SQL Server 2019 และแน่นอนและการกู้คืนฐานข้อมูลแบบเร่งด่วน (ซึ่งเป็นค่าปรับที่เปลี่ยนแปลงได้ด้วยเช่นกันทำให้สามารถย้อนกลับได้ทันทีโดยไม่คำนึงถึงขนาดของข้อมูล)


2
และเราทุกคนต่างก็เคยคุยกันว่า "มันใช้เวลานานในการย้อนกลับ
Mark Storey-Smith

ฉันเห็นลูกค้าจำนวนมากทำ บางคนออกมาโดยไม่ได้รับอันตราย แต่บางคนโชคดีน้อยกว่า
Aaron Bertrand

1
@ MarkStorey-Smith - หากคุณรีบูทการย้อนกลับกลางคัน SQL Server ไม่จำเป็นต้องทำการย้อนกลับเมื่อเริ่มต้นหรือไม่
Nick Chammas

2
@Nick นั้นขึ้นอยู่กับ - หากการย้อนกลับถูกบล็อกก่อนรีบูตตัวอย่างเช่นมันอาจทำงานเร็วขึ้นมากหลังจากรีสตาร์ทบริการเนื่องจากกระบวนการอื่นนั้นเพิ่งถูกฆ่า มี "สิ่งที่ถ้า" ในสถานการณ์นี้มากมาย - ทุกครั้งที่คุณรีบูทเซิร์ฟเวอร์หรือเริ่มบริการใหม่เพื่อ "แก้ไข" ปัญหาอาจมีปัญหาร้ายแรงบางอย่างเกิดขึ้น
Aaron Bertrand

2
@Nick ใช่ว่าเป็นสิ่งที่เกิดขึ้น ความคิดเห็นของฉันตั้งใจที่จะเป็น "ลิ้นในแก้ม" จนคุณต้องจบลงอย่างหลีกเลี่ยงไม่ได้ที่จะต้องอธิบายให้กับชาวบ้านที่มีความสุขที่เรียกที่ต้องการที่จะตีรีบูตเมื่อใดก็ตามที่มีพฤติกรรมไม่เป็นไปตามที่คาดไว้
Mark Storey-Smith

8

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

หากมีการใช้การย้อนกลับแทนจะเป็นการลบเครื่องหมายโกสต์ออกจากบันทึกเหล่านี้ไม่ใช่คำสั่งการแทรกที่เข้มข้น


ตัวอย่างที่ดีของวิธีการดำเนินการบางอย่างที่เหมาะสำหรับการย้อนกลับ
Mark Storey-Smith

5

ไม่ทั้งหมด PostgreSQL ไม่ต้องเสียเวลาในการย้อนกลับมากกว่าที่จะยอมรับเนื่องจากการดำเนินการทั้งสองนั้นเหมือนกันอย่างมีประสิทธิภาพในแง่ของดิสก์ I / O ฉันไม่คิดว่านี่เป็นคำถามของการปรับให้เหมาะสมสำหรับการคอมมิชชันมากเนื่องจากเป็นคำถามของสิ่งที่เคียวรีอื่น ๆ กำลังปรับให้เหมาะสม

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

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

อย่างไรก็ตามมันทำให้บางอย่างช้าลงเล็กน้อย ตัวอย่างเช่นการค้นหาคีย์หลักนั้นต้องสำรวจไฟล์ดัชนีและจากนั้นจะต้องกดปุ่มฮีปตาราง (สมมติว่าไม่มีการครอบคลุมดัชนีที่เกี่ยวข้อง) นี่ไม่ใช่เรื่องใหญ่โต แต่มันจะเพิ่มการค้นหาหน้าพิเศษหรืออาจเป็นการค้นหาหน้าแบบสุ่มเล็กน้อย (หากมีการปรับปรุงจำนวนมากเกิดขึ้นในแถวนั้น) เพื่อตรวจสอบข้อมูลและการมองเห็นอื่น ๆ

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

ดังนั้นฉันคิดว่าคำตอบที่แท้จริงคือ db ถูกปรับให้เหมาะสมสำหรับเวิร์กโหลดบางอย่างบนฝั่งอ่านและสิ่งนี้นำไปสู่ความท้าทายในด้านการเขียน โดยปกติแล้วจะมีคำถามอยู่บ่อยครั้งที่คอมมิชชันมักจะไม่ได้รับความนิยมมากกว่าการย้อนกลับ อย่างไรก็ตามสิ่งนี้ขึ้นอยู่กับความหมายของการทำสิ่งใดสิ่งหนึ่ง (การอัปเดตจะแตกต่างจากการลบ)


คำตอบที่ดี แต่มีคำพูดเล็กน้อย: "สำหรับ PostgreSQL ตารางทั้งหมดเป็นตารางฮีปและดัชนีแยกกันซึ่งหมายความว่าเมื่อย้อนกลับหรือกระทำไม่ต้องจัดเรียงข้อมูลใหม่" นี่ไม่ใช่เหตุผลที่ไม่มีข้อมูลที่จะต้อง จะจัดใหม่ค่อนข้างเป็นเพราะ "ฐานข้อมูลที่สำคัญซึ่งย้อนกลับช้ากว่ากระทำการย้ายข้อมูล" และ pg ไม่ตามที่คุณกล่าวถึง ออราเคิลยังใช้ค่าเริ่มต้นในการจัดเก็บฮีป: ความแตกต่างที่สำคัญคือออราเคิลใช้ 'เลิกทำ' และเรียกคืนพื้นที่ทั้งหมดในการคอมมิชชัน / ย้อนกลับแทนที่จะไปที่เส้นทาง 'สุญญากาศ'
Jack Douglas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.