ไม่สามารถหักล้างได้เมื่อเทียบกับที่ไม่แน่นอนเริ่มต้นทันที


92

ผมอ่านบทความนี้เกี่ยวกับ SQL คำหลักDEFERRABLEในฐานข้อมูลระบบ - หนังสือทั้งหมด

หลัง[ไม่ DEFERRABLE]เป็นค่าเริ่มต้นและหมายความว่าทุกครั้งที่มีการปรับเปลี่ยนฐานข้อมูลคำสั่งจะถูกดำเนินการข้อ จำกัด มีการตรวจสอบทันทีหลังจากนั้นหากการปรับเปลี่ยนอาจละเมิดข้อ จำกัด ต่างประเทศที่สำคัญ

อย่างไรก็ตามหากเราประกาศข้อ จำกัด ว่าDEFERRABLEเรามีตัวเลือกให้รอจนกว่าธุรกรรมจะเสร็จสมบูรณ์ก่อนที่จะตรวจสอบข้อ จำกัด

เราปฏิบัติตามคำหลักDEFERRABLEโดยขั้นแรกรอการตัดบัญชีหรือขั้นแรกทันที ในกรณีเดิมการตรวจสอบจะถูกเลื่อนออกไปก่อนที่จะมีการทำธุรกรรมแต่ละครั้ง ในกรณีหลังนี้จะมีการตรวจสอบทันทีหลังจากแต่ละคำสั่ง

เป็นวิธีการที่NOT DEFERRABLEแตกต่างจากDEFERRABLE INITIALLY IMMEDIATE? ในทั้งสองกรณีดูเหมือนว่าข้อ จำกัด ใด ๆ จะถูกตรวจสอบหลังจากแต่ละคำสั่ง

คำตอบ:


74

ด้วยDEFERRABLE INITIALLY IMMEDIATEคุณสามารถเลื่อนข้อ จำกัด ตามความต้องการได้เมื่อคุณต้องการ

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

ไวยากรณ์วิธีการเลื่อนข้อ จำกัด จะแตกต่างกันสำหรับ DBMS ต่างๆ

ด้วยการNOT DEFERRABLEที่คุณจะไม่เคยจะสามารถที่จะเลื่อนการตรวจสอบจนกว่าจะกระทำเวลา


1
@romkyns: DEFERRABLEระบุความตั้งใจของนักออกแบบว่าการเลื่อนข้อ จำกัด เป็นการกระทำที่คุ้มค่าหรือจำเป็น นี่ไม่ใช่กรณีสำหรับข้อ จำกัด ฐานข้อมูลส่วนใหญ่และการติดฉลากทั้งหมดเนื่องจากDEFERRABLEจะสูญเสียความแตกต่างที่เป็นประโยชน์นี้
onedaywhen

4
เมื่อเพื่อนร่วมงานของฉันได้ชี้ให้เห็นถึงเหตุผลที่ถูกต้องที่จริงแล้ว: คุณสามารถพึ่งพาข้อ จำกัด ที่ไม่สามารถเลื่อนเวลาได้ ณ จุดใด ๆ ของการทำธุรกรรมใด ๆ แต่ข้อ จำกัด ที่สามารถเลื่อนเวลาได้จะสังเกตได้เฉพาะในช่วงเริ่มต้นของธุรกรรมเท่านั้น
Roman Starkov

@RomanStarkov นอกจากนี้มันเป็นเรื่องของประสิทธิภาพ NOT DEFERRABLEมักจะเร็วที่สุด
Teejay

50

นอกเหนือจากคำตอบอื่น ๆ (ที่ถูกต้อง) เมื่อพูดถึง PostgreSQLจะต้องระบุว่า:

  • โดยที่ไม่สามารถแก้ไขได้แต่ละแถวจะถูกตรวจสอบในเวลาแทรก / อัปเดต

  • ด้วยDEFERRABLE (ในปัจจุบันทันที ) แถวทั้งหมดจะถูกตรวจสอบที่ส่วนท้ายของการแทรก / อัปเดต

  • กับDEFERRABLE (ปัจจุบันรอการตัดบัญชี ) แถวทั้งหมดจะถูกตรวจสอบในตอนท้ายของการทำธุรกรรม

ดังนั้นจึงไม่ถูกต้องที่จะบอกว่าข้อ จำกัด DEFERRABLE จะทำหน้าที่เหมือนไม่สามารถหักล้างได้เมื่อตั้งค่าเป็น IMMEDIATE


มาอธิบายรายละเอียดเกี่ยวกับความแตกต่างนี้:

CREATE TABLE example(
    row integer NOT NULL,
    col integer NOT NULL,
    UNIQUE (row, col) DEFERRABLE INITIALLY IMMEDIATE
);

INSERT INTO example (row, col) VALUES (1,1),(2,2),(3,3);

UPDATE example SET row = row + 1, col = col + 1;

SELECT * FROM example;

ผลลัพธ์นี้ถูกต้อง:

เอาท์พุท

แต่ถ้าเราเอาคำสั่ง DEFERRABLE INITIALLY IMMEDIATE ออก

ข้อผิดพลาด: ค่าคีย์ที่ซ้ำกันละเมิดข้อ จำกัด เฉพาะ "example_row_col_key" DETAIL: Key ("row", col) = (2, 2) มีอยู่แล้ว ********** ข้อผิดพลาด **********

ข้อผิดพลาด: ค่าคีย์ที่ซ้ำกันละเมิดข้อ จำกัด เฉพาะ "example_row_col_key" สถานะ SQL: 23505 รายละเอียด: มีคีย์ ("row", col) = (2, 2) อยู่แล้ว


ADDENDUM (12 ตุลาคม 2017)

พฤติกรรมนี้มีการบันทึกไว้ที่นี่ส่วน "ความเข้ากันได้":

นอกจากนี้ PostgreSQL จะตรวจสอบข้อ จำกัด เฉพาะที่ไม่สามารถเลื่อนเวลาได้ทันทีไม่ใช่ในตอนท้ายของคำสั่งตามที่มาตรฐานแนะนำ


น่าสนใจ. สำหรับฉันแล้วดูเหมือนว่าไม่มีเหตุผลใดที่จะชอบพฤติกรรม "ไม่แปรเปลี่ยน" กับพฤติกรรม "ทันทีทันใด" และมันก็สมเหตุสมผลที่ Postgres จะให้อภัยมากขึ้นและไม่ทำให้พฤติกรรมที่ไม่อาจปฏิเสธได้เหมือน "ทันที" ลำดับที่มีการอัปเดตแถวในคำสั่ง UPDATE ไม่ได้มีการจัดทำเป็นเอกสารหรือระบุไว้เท่าที่ฉันทราบดังนั้นพฤติกรรมของการตรวจสอบข้อ จำกัด ของคำสั่งกลางจึงไม่ได้ระบุไว้อย่างน้อยบางส่วนหรือไม่ ฉันไม่เห็นว่าทำไมใคร ๆก็ต้องการพฤติกรรมนั้น - แต่บางทีอาจมีกรณีการใช้งานที่สมเหตุสมผลที่ฉันขาดจินตนาการ
Mark Amery

1
ใช่พื้นเหตุผลเดียวที่จะต้องการNOT DEFERRABLEคือความเร็ว ( ดูที่นี่ส่วนไม่รอการตัดบัญชี จำกัด เอกลักษณ์ , "โปรดทราบว่านี้สามารถเป็นอย่างช้ากว่าการตรวจสอบเอกลักษณ์ทันที" )
Teejay

นอกจากนี้ยังมีDEFERRABLEข้อ จำกัด ไม่สามารถอ้างอิงเป็นคีย์ต่างประเทศในตารางอื่น ๆ ( ดูที่นี่ส่วนพารามิเตอร์ , "คอลัมน์อ้างอิงจะต้องเป็นคอลัมน์ของข้อ จำกัด ที่สำคัญไม่ใช่ deferrable ไม่ซ้ำกันหรือหลักในตารางที่อ้างถึง" )
Teejay

1
ตามหลักทั่วไปแล้วถ้ามันไม่สำคัญกับตรรกะทางธุรกิจจริงๆเมื่อมีการตรวจสอบข้อ จำกัด ฉันควรใช้ค่าเริ่มต้นNOT DEFERRABLEเพียงเพราะมันทำงานได้ดีกว่าหรือไม่?
dvtan

1
ในการออมของเราตอนนี้เราใช้กฎต่อไปนี้: 1) ถ้าข้อ จำกัด คือ PK เราจะใช้NOT DEFERRABLE2) ถ้าอย่างน้อยหนึ่ง FK อ้างอิง จำกัด เราใช้NOT DEFERRABLEเช่นกัน 3) ในกรณีอื่น ๆ DEFERRABLE INITIALLY IMMEDIATEที่เราใช้ สิ่งนี้อาจลดประสิทธิภาพของข้อ จำกัด เหล่านั้นเล็กน้อย แต่ช่วยให้มั่นใจได้ถึงความเข้ากันได้สูงสุดกับ DBMS อื่น ๆ ที่เราใช้ (Oracle, SqlServer) PK และ FK ไม่ใช่ปัญหาเพราะเราไม่เคยอัปเดตค่า (ซึ่งฉันคิดว่าเป็นนิสัยการเขียนโปรแกรมที่ดีสำหรับ DB)
Teejay

29

นอกเหนือจากความสามารถในการเลื่อนออกไปแล้วความแตกต่างก็คือประสิทธิภาพที่แท้จริง หากไม่มีการลงโทษด้านประสิทธิภาพก็ไม่จำเป็นต้องมีตัวเลือกในการเลือกเลื่อนเวลาออกไปหรือไม่ก็ได้ข้อ จำกัด ทั้งหมดจะเลื่อนออกไปได้

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


7

ฉันดึกมากไปงานเลี้ยง แต่ฉันต้องการที่จะเพิ่มที่ - ณ ธันวาคม 2018 - เพียงสองฐานข้อมูลที่ฉันรู้ (อาจจะมากขึ้นที่นั่น) มีระดับของการดำเนินการนี้บางคุณลักษณะมาตรฐาน SQL :

Database    NOT DEFERRABLE  DEFERRABLE           DEFERRABLE 
                            INITIALLY IMMEDIATE  INITIALLY DEFERRED
----------  --------------  -------------------  ------------------
Oracle      N/A *1          Yes (default)        Yes
PostgreSQL  Yes (default)   Yes                  Yes
DB2         -               -                    -
SQL Server  -               -                    -
MySQL       -               -                    -
MariaDB     -               -                    -
SAP Sybase  -               -                    -
HyperSQL    -               -                    -
H2          -               -                    -
Derby       -               -                    -

* 1 แม้ว่าออราเคิล 12c ยอมรับNOT DEFERRABLE รัฐ จำกัดDEFERRABLE INITIALLY IMMEDIATEก็จริงไม่สนใจมันและทำให้มันทำงานเป็น

อย่างที่คุณเห็น Oracle ไม่ได้ใช้ประเภทแรก ( NOT DEFERRABLE) และนั่นเป็นสาเหตุที่นักพัฒนาที่ใช้ Oracle (ในกรณีนี้ OP) อาจสับสนและพิจารณาว่าสองประเภทแรกเทียบเท่ากัน

น่าสนใจพอ Oracle และ PostgreSQL มีประเภทเริ่มต้นที่แตกต่างกัน อาจมีผลกระทบด้านประสิทธิภาพ


4

ไม่แน่นอน - คุณไม่สามารถเปลี่ยนแปลงการตรวจสอบข้อ จำกัด ได้ oracle จะตรวจสอบหลังจากแต่ละคำสั่ง (กล่าวคือโดยตรงหลังจากใส่คำสั่ง

หักล้างได้ทันที - oracle ตรวจสอบข้อ จำกัด หลังจากแต่ละคำสั่ง แต่คุณสามารถเปลี่ยนเป็นหลังการทำธุรกรรมแต่ละครั้ง (เช่นหลังจากกระทำ):

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