Chức năng so với Thủ tục được lưu trữ


88

Giả sử tôi phải triển khai một đoạn mã T-SQL mà kết quả là phải trả về một bảng. Tôi có thể triển khai một hàm giá trị bảng hoặc một thủ tục được lưu trữ khác trả về một tập hợp các hàng. Tôi nên sử dụng những gì?

Tóm lại, điều tôi muốn biết là:

Sự khác biệt chính giữa hàm và thủ tục được lưu trữ là gì? Tôi phải cân nhắc những gì khi sử dụng cái này hay cái kia?


1
Điều này dường như là câu trả lời hoàn hảo: stackoverflow.com/a/1179778/365188
Ozair Kafray

Câu trả lời:


51

Nếu bạn có khả năng muốn kết hợp kết quả của đoạn mã này với các bảng khác, thì rõ ràng một hàm định giá trị bảng sẽ cho phép bạn soạn kết quả trong một câu lệnh SELECT.

Nói chung, có một hệ thống phân cấp (Xem <Chức năng TV <Proc được lưu trữ). Bạn có thể làm được nhiều việc hơn trong từng cái, nhưng khả năng soạn kết quả đầu ra và để trình tối ưu hóa thực sự tham gia sẽ giảm khi chức năng tăng lên.

Vì vậy, hãy sử dụng bất kỳ giá trị nào tối thiểu cho phép bạn thể hiện kết quả mong muốn của mình.


50

Các hàm phải có tính xác định và không thể được sử dụng để thực hiện các thay đổi đối với cơ sở dữ liệu, trong khi các thủ tục được lưu trữ cho phép bạn thực hiện chèn và cập nhật, v.v.

Bạn nên hạn chế sử dụng các hàm, vì chúng gây ra vấn đề lớn về khả năng mở rộng cho các truy vấn lớn, phức tạp. Chúng trở thành một loại "hộp đen" cho trình tối ưu hóa truy vấn và bạn sẽ thấy sự khác biệt rất lớn về hiệu suất giữa việc sử dụng các hàm và chỉ cần chèn mã vào một truy vấn.

Nhưng chúng chắc chắn hữu ích cho lợi nhuận có giá trị bảng trong các trường hợp rất cụ thể.

Nếu bạn cần phân tích cú pháp một danh sách được phân tách bằng dấu phẩy, để mô phỏng việc chuyển một mảng vào một thủ tục, một hàm có thể biến danh sách thành một bảng cho bạn. Đây là thực tế phổ biến với Sql Server 2005, vì chúng tôi chưa thể chuyển các bảng vào các thủ tục được lưu trữ (chúng tôi có thể làm với 2008).


1
Nhưng bạn CÓ THỂ gửi XML đến một thủ tục được lưu trữ: stackoverflow.com/questions/144550/…
cllpse

2
Sai, hầu hết các chức năng máy chủ SQL là không xác định, chẳng hạn như getdate trong máy chủ MS-SQL. Chỉ các hàm ODBC là các hàm chuẩn (= nhanh hơn nhiều + có thể lập chỉ mục) ... Nhưng bạn nói rất đúng, nên hạn chế sử dụng các hàm trong truy vấn càng nhiều càng tốt vì lý do hiệu suất.
Stefan Steiger

45

Từ các tài liệu :

Nếu một thủ tục được lưu trữ đáp ứng các tiêu chí sau, nó là một ứng cử viên tốt để được viết lại dưới dạng một hàm có giá trị bảng:

  • Logic có thể diễn đạt được trong một câu lệnh SELECT nhưng là một thủ tục được lưu trữ, chứ không phải là một khung nhìn, chỉ vì nhu cầu tham số.

  • Thủ tục được lưu trữ không thực hiện các thao tác cập nhật, ngoại trừ các biến bảng.

  • Không cần câu lệnh EXECUTE động.

  • Thủ tục được lưu trữ trả về một tập kết quả.

  • Mục đích chính của thủ tục được lưu trữ là xây dựng các kết quả trung gian sẽ được tải vào một bảng tạm thời, sau đó được truy vấn trong một câu lệnh SELECT.


12

Tôi sẽ viết một số khác biệt thú vị giữa các thủ tục và hàm được lưu trữ.

  • Chúng ta có thể sử dụng các hàm trong các truy vấn được chọn nhưng chúng ta không thể sử dụng các thủ tục được lưu trữ trong các truy vấn được chọn.
  • Chúng ta không thể sử dụng các hàm không xác định trong Hàm nhưng chúng ta có thể sử dụng các hàm không xác định trong các thủ tục được lưu trữ. Bây giờ câu hỏi xuất hiện, hàm không xác định là gì .. Trả lời là: -

    Một hàm không xác định là hàm trả về các đầu ra khác nhau cho các giá trị đầu vào giống nhau tại các thời điểm khác nhau, như getdate (). Nó luôn trả về giá trị khác bất cứ khi nào nó được chạy.

    Ngoại lệ:-

    Các phiên bản trước của máy chủ sql trước sql 2000 không cho phép sử dụng hàm getdate () trong các hàm do người dùng xác định, nhưng phiên bản 2005 trở đi cho phép chúng tôi sử dụng hàm getdate () trong một hàm do người dùng xác định.

    Newid () là một ví dụ khác về hàm không xác định nhưng không thể được sử dụng trong các hàm do người dùng xác định nhưng chúng ta có thể sử dụng nó trong thủ tục được lưu trữ.

  • Chúng ta có thể sử dụng các câu lệnh DML (chèn, cập nhật, xóa) trong một thủ tục được lưu trữ nhưng chúng ta không thể sử dụng các câu lệnh DML trong các hàm trên bảng vật lý hoặc bảng vĩnh viễn. Nếu chúng ta muốn thực hiện thao tác DML trong các hàm, chúng ta có thể thực hiện nó trên các biến bảng không có trên các bảng vĩnh viễn.

  • Chúng tôi không thể sử dụng xử lý lỗi trong hàm nhưng chúng tôi có thể xử lý lỗi trong các thủ tục được lưu trữ.


Làm thế nào để các hoạt động DML được hỗ trợ trong các hàm MySQL?
Joey Pinto

@JoeyPinto. Bởi vì myNONsql không phải là lời phàn nàn về SQL. Chắc chắn, nó có các tính năng bổ sung, nhưng không phải là những điều cơ bản.
PerformanceDBA

8
  1. Thủ tục có thể trả về giá trị 0 hoặc n trong khi hàm có thể trả về một giá trị là bắt buộc.

  2. Các thủ tục có thể có các tham số đầu vào / đầu ra cho nó trong khi các hàm chỉ có thể có các tham số đầu vào.

  3. Thủ tục cho phép lựa chọn cũng như câu lệnh DML trong đó trong khi hàm chỉ cho phép câu lệnh lựa chọn trong đó.

  4. Các hàm có thể được gọi từ thủ tục trong khi các thủ tục không thể được gọi từ hàm.

  5. Ngoại lệ có thể được xử lý bằng khối try-catch trong một thủ tục trong khi khối try-catch không thể được sử dụng trong một hàm.

  6. Chúng tôi có thể quản lý giao dịch theo quy trình trong khi chúng tôi không thể thực hiện chức năng.

  7. Các thủ tục không thể được sử dụng trong một câu lệnh select trong khi hàm có thể được nhúng trong một câu lệnh select.

  8. UDF (Hàm do người dùng xác định) có thể được sử dụng trong các câu lệnh SQL ở bất kỳ đâu trong phần WHERE/ HAVING/ SELECTtrong khi không thể sử dụng các thủ tục được lưu trữ.

  9. Các UDF trả về bảng có thể được coi như một tập hợp hàng khác. Điều này có thể được sử dụng trong JOINs với các bảng khác.

  10. UDF nội tuyến có thể được coi là dạng xem nhận tham số và có thể được sử dụng trong JOINs và các hoạt động tập hợp hàng khác.


6

Ví dụ: nếu bạn có một hàm, bạn có thể sử dụng nó như một phần của câu lệnh SQL

SELECT function_name(field1) FROM table

Nó không hoạt động theo cách này đối với các thủ tục được lưu trữ.


1
Tôi nghĩ anh ấy đang nói về các hàm trả về giá trị bảng.
wcm

1
Tôi đang nói chung chung. Nhưng đối với trường hợp cụ thể của tôi, tôi hiện đang ở giữa một thủ tục được lưu trữ hoặc một hàm có giá trị bảng.
Auron

5

Tôi đã chạy một số bài kiểm tra với một bit logic chạy dài, với cùng một bit mã (một câu lệnh SELECT dài) chạy trong cả Hàm có giá trị bảng và Thủ tục được lưu trữ, và EXEC / SELECT thẳng và mỗi lệnh được thực hiện giống nhau.

Theo ý kiến ​​của tôi, luôn luôn sử dụng Hàm có giá trị bảng thay vì một thủ tục được lưu trữ để trả về một tập kết quả, vì nó làm cho logic dễ dàng hơn và dễ đọc hơn nhiều trong các truy vấn sau đó kết hợp với chúng và cho phép bạn sử dụng lại cùng một logic. Để tránh quá nhiều lần truy cập hiệu suất, tôi thường sử dụng các tham số "tùy chọn" (tức là bạn có thể chuyển NULL cho chúng) để kích hoạt chức năng trả về tập kết quả nhanh hơn, ví dụ:

CREATE FUNCTION dbo.getSitePermissions(@RegionID int, @optPersonID int, optSiteID int)
AS
RETURN 
    SELECT DISTINCT SiteID, PersonID
    FROM dbo.SiteViewPermissions
    WHERE (@optPersonID IS NULL OR @optPersonID = PersonID)
    AND (@optSiteID IS NULL OR @optSiteID = SiteID)
    AND @RegionID = RegionID

Bằng cách này, bạn có thể sử dụng chức năng này cho nhiều trường hợp khác nhau và không ảnh hưởng nhiều đến hiệu suất. Tôi tin rằng điều này hiệu quả hơn việc lọc sau đó:

SELECT * FROM dbo.getSitePermissions(@RegionID) WHERE SiteID = 1

Tôi đã sử dụng kỹ thuật này trong một số hàm, đôi khi với một danh sách dài các tham số "tùy chọn" thuộc loại này.


4

Cá nhân tôi sử dụng các hàm có giá trị bảng khi tất cả những gì tôi trả về là một bảng duy nhất không có ảnh hưởng. Về cơ bản, tôi coi chúng giống như các khung nhìn tham số hóa.

Nếu tôi cần trả lại nhiều tập bản ghi hoặc nếu sẽ có các giá trị được cập nhật trong bảng, tôi sử dụng một thủ tục được lưu trữ.

2 xu của tôi


4

Như đã đề cập ở trên, các hàm dễ đọc / có thể tổng hợp / tự lập tài liệu hơn, nhưng nhìn chung ít hiệu suất hơn và có thể kém hiệu quả hơn nghiêm trọng nếu bạn mang chúng đi trong các kết hợp chẳng hạn như

SELECT *
FROM dbo.tvfVeryLargeResultset1(@myVar1) tvf1
INNER JOIN dbo.tvfVeryLargeResultset1(@myVar2) tvf2
    ON (tvf1.JoinId = tvf2.JoinId)

Thông thường, bạn chỉ phải chấp nhận sự dư thừa của mã mà tvf có thể loại bỏ (với chi phí hiệu suất không thể chấp nhận được.)

Một điểm khác mà tôi chưa thấy đề cập là bạn không thể sử dụng bảng tạm thời thay đổi trạng thái cơ sở dữ liệu bên trong tvf nhiều câu lệnh. Cơ chế tương đương về mặt chức năng nhất với bảng tạm là biến bảng bộ nhớ không thay đổi trạng thái, và đối với tập dữ liệu lớn, bảng tạm thời có thể sẽ hoạt động hiệu quả hơn biến bảng. (Các lựa chọn thay thế khác bao gồm bảng động & biểu thức có giá trị bảng thông thường, nhưng ở một số mức độ phức tạp, chúng không còn là một lựa chọn tốt IMO.)


1

Tôi sẽ kiểm tra hiệu suất cả hai. Có thể cách tiếp cận sp hoặc một bảng dẫn xuất sẽ nhanh hơn đáng kể so với một hàm và nếu vậy nên sử dụng cách tiếp cận đó. Nói chung, tôi tránh các chức năng vì chúng có thể là hiệu suất.


1

Nó phụ thuộc :) Nếu bạn muốn sử dụng kết quả có giá trị bảng trong một thủ tục khác, bạn nên sử dụng Hàm TableValued. Nếu kết quả dành cho máy khách, thì thông thường, proc được lưu trữ là cách tốt hơn để thực hiện.


-1

Các thủ tục được lưu trữ là các truy vấn được biên dịch trước, thực thi nhanh hơn và tiết kiệm từ việc tiêm sql. Chúng có thể trả về giá trị 0 hoặc N. Chúng ta có thể thực hiện các thao tác DML bên trong các thủ tục được lưu trữ. Chúng ta có thể sử dụng các hàm bên trong các thủ tục và có thể sử dụng các hàm trong truy vấn chọn. Các hàm được sử dụng để trả về bất kỳ giá trị nào và các hoạt động DML không thể thực hiện được trong các hàm. hàm có hai loại vô hướng và có giá trị theo bảng. hàm vô hướng trả về một giá trị duy nhất, hàm có giá trị theo bảng được sử dụng để trả về các hàng của bảng.


Đây là một câu hỏi rất cũ với số lượng lớn các câu trả lời, nhiều câu trả lời (bao gồm cả câu trả lời được chấp nhận) được ủng hộ cao. Trước khi thêm một câu trả lời khác vào một chủ đề như vậy, bạn nên tự hỏi mình, "tất cả những câu trả lời hiện có thiếu điều gì mà yêu cầu tôi viết một câu khác?"
APC
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.