KHÔNG CÓ THỂ XÁC ĐỊNH so với CÓ THỂ XÁC ĐỊNH BAN ĐẦU NGAY LẬP TỨC


90

Tôi đọc điều này về từ khóa SQL DEFERRABLEtrong Hệ thống cơ sở dữ liệu - Toàn tập .

Sau đó [KHÔNG DEFERRABLE] là mặc định, và các phương tiện mà mỗi lần một tuyên bố sửa đổi cơ sở dữ liệu được thực thi, các hạn chế được kiểm tra ngay lập tức sau đó, nếu việc sửa đổi có thể vi phạm các hạn chế foreign-key.

Tuy nhiên, nếu chúng ta khai báo một ràng buộc là DEFERRABLE , thì chúng ta có tùy chọn để nó đợi cho đến khi một giao dịch hoàn tất trước khi kiểm tra ràng buộc.

Chúng tôi làm theo từ khóa DEFERRABLE bởi một trong hai ban đầu HOÃN hoặc ban đầu NGAY . Trong trường hợp trước đây, việc kiểm tra sẽ được hoãn lại ngay trước khi thực hiện mỗi giao dịch. Trong trường hợp thứ hai, việc kiểm tra sẽ được thực hiện ngay sau mỗi tuyên bố.

Khác như thế nào NOT DEFERRABLEvới DEFERRABLE INITIALLY IMMEDIATE? Trong cả hai trường hợp, dường như mọi ràng buộc đều được kiểm tra sau mỗi câu lệnh riêng lẻ.

Câu trả lời:


72

Với DEFERRABLE INITIALLY IMMEDIATEbạn có thể trì hoãn các ràng buộc theo yêu cầu khi bạn cần.

Điều này hữu ích nếu bạn thường muốn kiểm tra các ràng buộc tại thời điểm phát biểu, nhưng ví dụ: tải hàng loạt muốn trì hoãn việc kiểm tra cho đến thời gian cam kết.

Tuy nhiên, cú pháp cách trì hoãn các ràng buộc là khác nhau đối với các DBMS khác nhau.

Với NOT DEFERRABLEbạn sẽ không bao giờ có thể trì hoãn việc kiểm tra cho đến thời gian cam kết.


1
@romkyns: DEFERRABLEnêu ý định của nhà thiết kế rằng việc trì hoãn ràng buộc là một hành động đáng giá hoặc cần thiết. Đây không phải là trường hợp của phần lớn các ràng buộc cơ sở dữ liệu và việc dán nhãn tất cả vì DEFERRABLEsẽ làm mất đi sự khác biệt hữu ích này.
onedaywhen

4
@onedaywhen Một đồng nghiệp của tôi kể từ đó đã chỉ ra một lý do hợp lệ, thực sự: bạn có thể dựa vào các ràng buộc không thể hoãn lại tại bất kỳ thời điểm nào của bất kỳ giao dịch nào, nhưng các ràng buộc có thể hoãn lại chỉ được quan sát thấy khi bắt đầu giao dịch.
Roman Starkov

@RomanStarkov Ngoài ra, đó là vấn đề về hiệu suất. NOT DEFERRABLEthường là nhanh nhất.
Teejay 20/1218

46

Ngoài các câu trả lời (đúng) khác, khi nói về PostgreSQL , phải nói rằng:

  • với NOT DEFERRABLE mỗi hàng được kiểm tra tại thời điểm chèn / cập nhật

  • với DEFERRABLE (hiện tại NGAY LẬP TỨC ) tất cả các hàng được chọn ở cuối phần chèn / cập nhật

  • với DEFERRABLE (hiện HOÃN ) tất cả các hàng đều được kiểm tra ở phần cuối của giao dịch

Vì vậy, không đúng khi nói rằng một ràng buộc DEFERRABLE hoạt động giống như một ràng buộc NOT DEFERRABLE khi nó được đặt thành NGAY LẬP TỨC.


Hãy nói rõ về sự khác biệt này:

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;

Điều này đầu ra chính xác:

đầu ra

Nhưng nếu chúng ta xóa hướng dẫn CÓ THỂ BẤT NGỜ NGAY LẬP TỨC,

LỖI: giá trị khóa trùng lặp vi phạm ràng buộc duy nhất "example_row_col_key" CHI TIẾT: Khóa ("hàng", col) = (2, 2) đã tồn tại. ********** Lỗi **********

LỖI: giá trị khóa trùng lặp vi phạm ràng buộc duy nhất "example_row_col_key" Trạng thái SQL: 23505 Chi tiết: Khóa ("row", col) = (2, 2) đã tồn tại.


ADDENDUM (ngày 12 tháng 10 năm 2017)

Hành vi này thực sự được ghi lại ở đây , phần "Khả năng tương thích":

Ngoài ra, PostgreSQL kiểm tra các ràng buộc về tính duy nhất không thể trì hoãn ngay lập tức, không phải ở cuối câu lệnh như tiêu chuẩn sẽ đề xuất.


Hấp dẫn. Đối với tôi, có vẻ như về cơ bản không có lý do gì để thích hành vi "KHÔNG KHẮC PHỤC" hơn hành vi "NGAY LẬP TỨC" và điều đó có nghĩa là Postgres sẽ dễ dàng tha thứ hơn và làm cho hành vi KHÔNG KHẮC PHỤC như "NGAY LẬP TỨC". Thứ tự các hàng được cập nhật trong câu lệnh UPDATE thậm chí không được ghi lại hoặc chỉ rõ theo như tôi biết, vì vậy, không phải hành vi của việc kiểm tra ràng buộc giữa câu lệnh này ít nhất là một phần không xác định? Tôi không thể hiểu tại sao bất kỳ ai cũng muốn hành vi đó - nhưng có lẽ có một trường hợp sử dụng hợp lý cho nó mà tôi thiếu trí tưởng tượng để xem.
Mark Amery

1
Có, về cơ bản lý do duy nhất để thích NOT DEFERRABLElà tốc độ ( xem tại đây , phần Ràng buộc về tính duy nhất không được trì hoãn , "Hãy lưu ý rằng điều này có thể chậm hơn đáng kể so với việc kiểm tra tính duy nhất tức thì" ).
Teejay

Ngoài ra, DEFERRABLEràng buộc không thể được tham chiếu như khóa ngoại trong các bảng khác ( xem tại đây , phần Tham số , "Các cột được tham chiếu phải là cột của ràng buộc khóa chính hoặc duy nhất không thể trì hoãn trong bảng được tham chiếu" ).
Teejay

1
Vì vậy, theo nguyên tắc chung, nếu nó không thực sự quan trọng đối với logic nghiệp vụ khi ràng buộc được kiểm tra, thì tôi có nên mặc định sử dụng NOT DEFERRABLEchỉ vì nó hoạt động tốt hơn không?
dvtan

1
Trong ORM của chúng tôi, chúng tôi sử dụng các quy tắc sau: 1) nếu ràng buộc là một PK, chúng tôi sử dụng NOT DEFERRABLE2) nếu ít nhất một FK tham chiếu đến ràng buộc, chúng tôi cũng sử dụng NOT DEFERRABLE3) trong các trường hợp khác, chúng tôi sử dụng DEFERRABLE INITIALLY IMMEDIATE. Điều này có thể làm giảm một chút hiệu suất của những ràng buộc đó, nhưng đảm bảo khả năng tương thích tối đa với các DBMS khác mà chúng tôi sử dụng (Oracle, SqlServer). PK và FK không phải là một vấn đề vì chúng tôi không bao giờ cập nhật các giá trị của chúng (tôi nghĩ đó là một thói quen lập trình tốt cho các DB).
Teejay

29

Ngoài sự rõ ràng của việc có thể trì hoãn, sự khác biệt thực sự là hiệu suất. Nếu không có hình phạt hiệu suất thì sẽ không cần phải có tùy chọn để chọn có thể hoãn lại hoặc không - tất cả các ràng buộc chỉ đơn giản là có thể hoãn lại.

Hình phạt hiệu suất liên quan đến các tối ưu hóa mà cơ sở dữ liệu có thể thực hiện với kiến ​​thức về cách dữ liệu bị hạn chế. Ví dụ, chỉ mục được tạo để hỗ trợ một ràng buộc duy nhất trong Oracle không thể là một chỉ mục duy nhất nếu ràng buộc có thể hoãn lại vì phải cho phép tạm thời các bản sao. Tuy nhiên, nếu ràng buộc không thể trì hoãn thì chỉ mục có thể là duy nhất.


7

Tôi đến rất muộn nhưng tôi muốn nói thêm rằng - kể từ tháng 12 năm 2018 - chỉ có hai cơ sở dữ liệu mà tôi biết (có thể còn nhiều hơn nữa) cung cấp một số cấp độ triển khai tính năng SQL tiêu chuẩn này :

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 Mặc dù Oracle 12c chấp nhận NOT DEFERRABLE trạng thái ràng buộc , nó thực sự bỏ qua nó và làm cho nó hoạt động như bình thường DEFERRABLE INITIALLY IMMEDIATE.

Như bạn thấy, Oracle không triển khai kiểu đầu tiên ( NOT DEFERRABLE), và đó là lý do tại sao các nhà phát triển sử dụng Oracle (OP trong trường hợp này) có thể nhầm lẫn và coi hai kiểu đầu tiên là tương đương nhau.

Điều thú vị là Oracle và PostgreSQL có một kiểu mặc định khác nhau. Có thể nó có ý nghĩa về hiệu suất.


4

NOT DEFERRABLE - bạn không thể thay đổi việc kiểm tra ràng buộc, oracle sẽ kiểm tra nó sau mỗi câu lệnh (tức là trực tiếp sau câu lệnh insert).

DEFERRABLE BAN ĐẦU NGAY LẬP TỨC - oracle kiểm tra ràng buộc sau mỗi câu lệnh. NHƯNG, bạn có thể thay đổi nó thành sau mỗi giao dịch (tức là sau khi cam kết):

set constraint pk_tab1 deferred;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.