2012-03-29 22 views
13

Chúng tôi vừa nâng cấp từ Oracle 10 lên Oracle 11.2. Sau khi nâng cấp, tôi bắt đầu thấy một lỗi bảng đột biến gây ra bởi một hàm thay vì một trình kích hoạt (mà trước đây tôi chưa từng gặp). Đó là mã cũ đã làm việc trong các phiên bản trước của Oracle.Bảng đột biến trong Oracle 11 do một hàm

Dưới đây là một kịch bản mà sẽ gây ra lỗi:

create table mutate (
    x NUMBER, 
    y NUMBER 
); 

insert into mutate (x, y) 
values (1,2); 

insert into mutate (x, y) 
values (3,4); 

tôi đã tạo ra hai hàng. Bây giờ, tôi sẽ tăng gấp đôi các hàng của mình bằng cách gọi tuyên bố này:

insert into mutate (x, y) 
select x + 1, y + 1 
from mutate; 

Đây không phải là điều cần thiết để sao chép lỗi, nhưng nó sẽ giúp với trình diễn sau này. Vì vậy, nội dung của bảng giờ trông giống như sau:

X,Y 
1,2 
3,4 
2,3 
4,5 

Tất cả đều tốt. Bây giờ cho phần thú vị:

create or replace function mutate_count 
return PLS_INTEGER 
is 
    v_dummy PLS_INTEGER; 
begin 
    select count(*) 
    into v_dummy 
    from mutate; 

    return v_dummy; 
end mutate_count; 
/

Tôi đã tạo một hàm để truy vấn bảng và trả về một số. Bây giờ, tôi sẽ kết hợp điều đó với câu lệnh INSERT:

insert into mutate (x, y) 
select x + 2, y + 2 
from mutate 
where mutate_count() = 4; 

Kết quả? Lỗi này:

ORA-04091: table MUTATE is mutating, trigger/function may not see it 
ORA-06512: at "MUTATE_COUNT", line 6 

Vì vậy, tôi biết những gì gây ra lỗi, nhưng tôi tò mò như với tại sao. Oracle không thực hiện SELECT, truy xuất tập kết quả và sau đó thực hiện chèn hàng loạt các kết quả đó? Tôi sẽ chỉ mong đợi một lỗi bảng đột biến nếu các bản ghi đã được chèn trước khi truy vấn kết thúc. Nhưng nếu Oracle đã làm điều đó, sẽ không tuyên bố trước đó:

insert into mutate (x, y) 
select x + 1, y + 1 
from mutate; 

bắt đầu một vòng lặp vô hạn?

UPDATE:

Qua liên kết Jeffrey Tôi thấy điều này trong the Oracle docs:

By default, Oracle guarantees statement-level read consistency. The set of data returned by a single query is consistent with respect to a single point in time.

Ngoài ra còn có một bình luận từ các tác giả trong his post:

One could argue why Oracle doesn't ensure this 'statement-level read consistency' for repeated function calls that appear inside a SQL statement. It could be considered a bug as far as I'm concerned. But this is the way it currently works.

Tôi thích hợp trong giả định rằng điều này hành vi đã thay đổi giữa Oracle phiên bản 10 và 11?

Trả lời

9

Thứ nhất,

insert into mutate (x, y) 
select x + 1, y + 1 
from mutate; 

Không bắt đầu một vòng lặp vô hạn, bởi vì các truy vấn sẽ không thấy các dữ liệu đã được chèn - chỉ dữ liệu đã tồn tại như sự bắt đầu của báo cáo kết quả. Các hàng mới sẽ chỉ hiển thị cho các câu lệnh tiếp theo.

This giải thích nó khá tốt:

When Oracle steps out of the SQL-engine that's currently executing the update statement, and invokes the function, then this function -- just like an after row update trigger would -- sees the intermediate states of EMP as they exist during execution of the update statement. This implies that the return value of our function invocations heavily depend on the order in which the rows happen to be updated.

+0

Liên kết tốt, cảm ơn! Tôi sẽ cập nhật câu hỏi của mình và để nó mở một chút để xem nó có tạo ra bất kỳ cuộc thảo luận bổ sung nào không. –

+0

+1 bạn có điểm về lý do tại sao nó xảy ra – zep

+0

Điều này đã giúp, nhưng có câu hỏi làm rõ ... Có thể hàm tồn tại trong Gói được gọi từ trình kích hoạt trước khi cập nhật không? Tôi đang có một cơn ác mộng của những vấn đề như nhiều người khác do Oracles crappy gây nên. –

8

Tuyên bố Cấp đọc nhất quán và giao dịch Cấp đọc nhất quán".

Từ hướng dẫn:

"If a SELECT list contains a function, then the database applies statement-level read consistency at the statement level for SQL run within the PL/SQL function code, rather than at the parent SQL level. For example, a function could access a table whose data is changed and committed by another user. For each execution of the SELECT in the function, a new read consistent snapshot is established".

Cả hai khái niệm được giải thích trong "Oracle® Các khái niệm cơ sở dữ liệu":

http://download.oracle.com/docs/cd/B19306_01/server.102/b14220/consist.htm#sthref1955


- >>>CẬP NHẬT

- >>> * Mục thêm vào sau khi OP đã được đóng

Nguyên tắc

Nguyên tắc kỹ thuật, cũng được liên kết bởi ông Kemp (@ jeffrey-kemp) và cũng giải thích bởi Toon Koppelaars here, được báo cáo trong "tài liệu tham khảo PL/SQL ngôn ngữ - kiểm soát tác dụng phụ của PL/SQL subprograms" (chức năng của bạn vi phạm RNDS đọc không một quốc gia cơ sở dữ liệu):

When invoked from an INSERT, UPDATE, or DELETE statement, the function cannot query or modify any database tables modified by that statement.

If a function either queries or modifies a table, and a DML statement on that table invokes the function, then ORA-04091 (mutating-table error) occurs.

PL/SQL Functions that SQL Statements Can Invoke

+0

Điều cần biết! Điều đó có vẻ giống như một lý do tốt khác để tránh các cuộc gọi hàm trong các câu lệnh SQL càng nhiều càng tốt, ngoài việc xem xét hiệu suất - chúng vi phạm quy tắc chụp nhanh cấp độ gốc của SQL. –

+0

@ Dan-A. Tôi sử dụng chúng để đơn giản hóa các tính toán phức tạp khi giá trị hàng trong các hàm xác định nơi chúng không vi phạm WNDS và RNDS (không ghi trạng thái dữ liệu và không đọc trạng thái dữ liệu). – zep

Các vấn đề liên quan