Tôi có thể dựa vào các hàm được thực thi đầu tiên trong SQL không


9

Vui lòng xem xét các kịch bản sau đây:

create or replace function f(p_limit in integer) return integer as
begin
  set_global_context ('limit', p_limit);
  return p_limit;
end;
/

create view v as 
select level as val from dual connect by level<=sys_context('global_context','limit');

select f(2), v.* from v;

/*
F(2)                   VAL                    
---------------------- ---------------------- 
2                      1                      
2                      2                      
*/

select f(4), v.* from v;

/*
F(4)                   VAL                    
---------------------- ---------------------- 
4                      1                      
4                      2                      
4                      3                      
4                      4                      
*/

Tôi có thể dựa vào f(x)việc được thực thi trước khi bối cảnh được đọc bên trong khung nhìn không, vì nó đã có trong trường hợp thử nghiệm này chạy trên 10.2?


Không thể không nghĩ rằng một kích hoạt đăng nhập có thể phù hợp hơn (nếu mức độ sẽ luôn giống nhau, đó là)
Phil

@Phil đây chỉ là một ví dụ - Tôi đang sử dụng sys_context để tạo tham số cho chế độ xem và thông số sẽ khác nhau mỗi lần. Nếu bạn biết một cách để đặt bối cảnh toàn cầu từ SQL mà không phải loay hoay như thế này thì tôi cũng rất muốn nghe điều đó!
Jack nói hãy thử topanswers.xyz

1
@JackDoureb: parameteraising một quan điểm là một ý tưởng không "cảm thấy" đúng với tôi. Trong MSSQL, những gì bạn đang cố gắng có thể được thực hiện bằng cách sử dụng hàm do người dùng xác định trả về tập kết quả (thay vì giá trị), - sau đó bạn có thể SELECT stuff FROM dbo.FuncReturningTable(param)hoặc tương tự. Oracle có thể có chức năng tương đương. Mặc dù nếu sử dụng điều này trên các tập dữ liệu lớn, tôi sẽ cẩn thận theo dõi hiệu suất: Tôi không chắc người lập kế hoạch truy vấn cần sáng đến mức nào để thực hiện một kế hoạch hiệu quả từ cú pháp đó.
David Spillett

@David parameteraising một chế độ xem thường được thực hiện với sys_context - thông thường bạn sẽ đặt bối cảnh trước khi thực hiện truy vấn (ví dụ: với một chút PL / SQL). Oracle có các hàm thiết lập trở lại và / hoặc đường ống nhưng chúng không phải là cách 'bình thường' để đạt được điều này. Để rõ ràng, tôi nghĩ rằng câu trả lời cho câu hỏi trong tiêu đề là "không" - tôi chỉ tự hỏi nếu ai đó biết rõ hơn.
Jack nói hãy thử topanswers.xyz

Câu trả lời:


8

Không.

Nếu bạn viết lại chế độ xem của mình bằng bộ lọc ngữ cảnh theo mệnh đề where (thay vì kết nối bởi), bạn sẽ nhận được giá trị được đặt trước đó cho ngữ cảnh:

create table t as 
 select rownum r from dual connect by level <= 10;

create or replace view v as 
  select r val from t where r <=sys_context('global_context','limit');

select f(2), v.* from v;

F(2) VAL
---- ---
   2   1 
   2   2 

select f(4), v.* from v;

F(4) VAL
---- ---
   4   1 
   4   2 

select f(4), v.* from v;

F(4) VAL
---- ---
   4   1 
   4   2 
   4   3 
   4   4 

Vì mệnh đề where được ước tính trước khi các cột được chọn, giá trị được truyền cho hàm không được đặt cho đến khi bối cảnh được đọc. Vị trí của lệnh gọi sys_context trong truy vấn của bạn (chọn, ở đâu, nhóm theo, v.v.) sẽ ảnh hưởng chính xác khi giá trị này được đặt.


+1 đó là khá nhiều "trường hợp đóng" trong cuốn sách của tôi, cảm ơn.
Jack nói hãy thử topanswers.xyz

2

Nói chung, bạn không thể giả định một cách an toàn bất cứ điều gì về thứ tự DBMS của bạn sẽ làm mọi thứ khi đánh giá một câu lệnh SQL. Đây là lý do tại sao nhiều DBMS sẽ không cho phép các hàm được sử dụng theo cách đó có tác dụng phụ (tức là MSSQL sẽ không cho phép các hàm đặt trạng thái toàn cầu / kết nối mà bạn đang thực hiện ở đó hoặc thay đổi nội dung bảng). Một loạt các câu lệnh phải được thực thi theo cách có ý nghĩa từ bước này sang bước tiếp theo (nghĩa là chúng được chạy một cách thanh thản hoặc theo cách mà bạn không thể nói chúng không phải), nhưng trong một câu lệnh, trình hoạch định truy vấn có thời gian trị vì miễn phí, nó không giới thiệu sự mơ hồ nơi nó chưa tồn tại (trong ví dụ của bạn đã có sự mơ hồ vì chức năng này có tác dụng phụ ảnh hưởng đến chế độ xem).

Nếu trình hoạch định truy vấn đủ sáng để phát hiện chế độ xem bị ảnh hưởng bởi các tác dụng phụ của chức năng, thì bạn sẽ làm gì nếu bạn tham gia vào một chế độ xem khác có chức năng đó với các giá trị đầu vào khác nhau? Nó có thể khá nhanh chóng có nhiều lông - loại điều này là lý do tại sao nói chung, trong bất kỳ bối cảnh lập trình nào, các hàm không nên có hiệu ứng vượt quá đầu ra của chính chúng.

Trong ví dụ cụ thể này, tôi sẽ nói rằng không chắc là f (x) sẽ được gọi đầu tiên, vì đó là phần "hiển thị" của câu lệnh: kết quả được đặt từ chế độ xem có thể được truy xuất trước bất kỳ hàm nào trong danh sách các cột để trả lại được đánh giá. Tất nhiên điều này sẽ thay đổi tùy thuộc vào DBMS được sử dụng: Tôi không phải là chuyên gia của Oracle và kết quả kiểm tra của bạn cho thấy rằng chức năng dường như được gọi đầu tiên trong các trường hợp này. Nhưng tôi sẽ cảnh giác khi dựa vào thứ tự thực thi trong bất kỳ câu lệnh SQL nào giống nhau - ngay cả khi nó luôn hoạt động theo cách bạn mong đợi ngay bây giờ, nó có thể không làm như vậy trong các phiên bản trong tương lai (trừ khi nó được ghi lại chính thức ở đâu đó cách này xung quanh).


2
Câu trả lời tốt, nhưng tôi cảm thấy rằng Jack đang tìm kiếm một câu trả lời kỹ thuật dứt khoát của Oracle.
Phil

1

Tài liệu chỉ hứa hẹn rằng "Trình tối ưu hóa trước tiên đánh giá các biểu thức và điều kiện chứa hằng số một cách đầy đủ nhất có thể." ( 10.2 , 11.2 ). Bạn không được đảm bảo rằng nó sẽ đánh giá bất kỳ biểu thức cụ thể nào trước tiên hoặc nó sẽ không thay đổi thứ tự đó theo thời gian (một bản vá mới trong cùng một bản phát hành?).


+1 xuất sắc, cảm ơn (mặc dù tôi đã đọc những tài liệu đó không hoàn toàn vuông với câu trả lời của Chris )
Jack nói hãy thử topanswers.xyz

1
Sự khác biệt là liệu hàm được gọi trong mệnh đề where, select hay một số mệnh đề khác. Các chức năng trong phần được chọn sẽ không ảnh hưởng đến các quyết định tối ưu hóa (trừ khi đó là truy vấn con), vì vậy chúng không cần được đánh giá cho đến khi tìm nạp kết quả. Các hàm trong mệnh đề where sẽ ảnh hưởng đến phương thức nối được sử dụng, do đó cần phải được đánh giá càng sớm càng tốt.
Chris Saxon

@Chris là kinh nghiệm nói hay bạn đã nhận được điều đó từ các tài liệu ở đâu đó?
Jack nói hãy thử topanswers.xyz

Tôi không thể tìm thấy một tài liệu tham khảo. Dựa trên kinh nghiệm của tôi, nếu được gọi trong mệnh đề where để lọc một bảng duy nhất, nó sẽ được truy cập cho mỗi hàng (giả sử FTS), nhưng chỉ cho các hàng được trả về nếu trong danh sách chọn. Vì kế hoạch thực hiện được thiết lập trong quá trình phân tích cú pháp, điều này ngụ ý rằng các chức năng trong lựa chọn không thể ảnh hưởng đến nó. Một trường hợp thử nghiệm để kiểm tra điều này có thể được thực hiện bằng cách tạo một hàm đặt bộ đếm (trong gói hoặc bảng) và so sánh đầu ra dựa trên vị trí của truy vấn.
Chris Saxon
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.