2008-10-07 56 views
83

Giả sử tôi phải triển khai một đoạn mã T-SQL phải trả về bảng như là kết quả. Tôi có thể thực hiện một hàm có 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 cái gì?Chức năng so với các thủ tục được lưu trữ

Nói tóm lại, những gì tôi muốn biết là:

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

+1

Đây có vẻ là câu trả lời hoàn hảo: http://stackoverflow.com/a/1179778/365188 –

Trả lời

48

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 hàm bảng có giá trị 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 truyền hình < Proc được lưu trữ). Bạn có thể làm được nhiều hơn trong mỗi công cụ, nhưng khả năng soạn kết quả đầu ra, và để trình tối ưu hóa thực sự giảm bớt khi chức năng tăng lên.

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

4

Cá nhân tôi sử dụng các hàm có giá trị bảng khi tất cả tôi đang quay trở lại là một bảng duy nhất không có ảnh hưởng. Về cơ bản tôi đối xử với họ như quan điểm tham số hóa.

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

2 cent Mỹ

6

Nếu bạn có một chức năng bạn có thể sử dụng nó như là một phần của câu lệnh SQL của bạn, ví dụ

SELECT function_name(field1) FROM table 

Nó không làm việc theo cách này cho các thủ tụ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

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

48

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

Bạn nên hạn chế việc bạn sử dụng chức năng này, kể từ khi họ đặt ra một khổng lồ vấn đề 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 "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 truy vấn.

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

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

+1

Nhưng bạn CÓ THỂ gửi XML đến một thủ tục được lưu trữ: http://stackoverflow.com/questions/144550/sql-server-dynamic-where-clause – roosteronacid

+2

Sai, hầu hết các hàm máy chủ SQL không xác định, chẳng hạn như getdate trong MS- Máy chủ 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 được) ... Nhưng bạn rất đúng, ta nên hạn chế việc sử dụng các hàm trong các truy vấn càng nhiều càng tốt vì các lý do hiệu suất. –

1

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

41

From the docs:

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

  • Logic thể diễn tả được trong một đơn 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ì sự cần thiết cho các tham số.

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

  • Không cần báo cáo động EXECUTE.

  • Quy trình được lưu trữ trả về một tập hợp kết quả.

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

1

Tôi sẽ thử nghiệm perfromance cả hai. Nó có khả năng là 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 cách tiếp cận đó nên được sử dụng. Nói chung tôi tránh các chức năng bởi vì chúng có thể là heo hiệu suất.

4

Như đã đề cập ở trên, chức năng là dễ đọc hơn/composable/tự chủ tài liệu, nhưng ít performant nói chung, và có thể nghiêm túc ít performant nếu bạn được mang đi với họ trong tham gia như

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

Thường , bạn chỉ cần chấp nhận sự 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 từng đề cập là bạn không thể sử dụng temp thay đổi trạng thái cơ sở dữ liệu bảng bên trong của một tvf đa tuyên bố. Cơ chế tương đương về chức năng nhất với bảng tạm thời là thay đổi không phải trạng thái, trong biến bảng bộ nhớ và đối với các tập dữ liệu lớn, bảng tạm thời có thể có hiệu suất cao hơn biến bảng. (Các lựa chọn thay thế khác bao gồm các bảng động & các bảng chung có giá trị biểu thức, nhưng ở mức độ phức tạp nào đó, chúng không còn là một lựa chọn tốt nữa IMO.)

+0

Bạn đã đạt được điểm tốt! Cảm ơn! – Auron

5

Tôi chạy một số thử nghiệm với một chút logic dài, với cùng một bit mã (một phát biểu SELECT dài) chạy trong cả một hàm bảng có giá trị và một thủ tục lưu trữ, và một EXEC/SELECT thẳng, và mỗi thực hiện giống hệt nhau. Theo quan điểm của tôi, luôn sử dụng một hàm Table Valued thay vì một thủ tục lưu sẵn để 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 trong các truy vấn sau đó tham gia vào chúng và cho phép bạn sử dụng lại cùng một logic. Để tránh quá nhiều của một hit hiệu suất, tôi thường sử dụng "tùy chọn" thông số (ví dụ: bạn có thể vượt qua NULL cho họ) để kích hoạt chức năng trả lại kết quả thiết lập để được 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 tình huống khác nhau, và không có một hit hiệu suất rất lớn.Tôi tin rằng điều này hiệu quả hơn 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ố chức năng, đôi khi có danh sách dài các tham số "tùy chọn" của loại này.

8
  1. Quy trình có thể trả về giá trị 0 hoặc n trong khi hàm có thể trả lại một giá trị bắt buộc.

  2. Quy trình có thể có tham số đầu vào/đầu ra cho nó trong khi các hàm chỉ có thể có tham số đầu vào.

  3. Quy trình cho phép chọn cũng như câu lệnh DML trong khi chức năng chỉ cho phép chọn câu lệnh trong đó.

  4. Các chức năng có thể được gọi từ quy trình trong khi các thủ tục không thể là được gọi từ hàm.

  5. Ngoại lệ có thể được xử lý bởi khối try-catch trong một quy trình 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 trong quy trình trong khi chúng tôi không thể hoạt động.

  7. Thủ tục không thể được sử dụng trong câu lệnh chọn trong khi chức năng có thể được nhúng vào một câu lệnh chọn.

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

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

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

10

Tôi sẽ viết vài sự khác biệt thú vị giữa các thủ tục và chức năng được lưu trữ.

  • Chúng tôi có thể sử dụng các chức năng trong các truy vấn chọn nhưng chúng tôi không thể sử dụng các thủ tục được lưu trữ trong các truy vấn chọn lọc.
  • Chúng tôi không thể sử dụng các hàm không xác định trong Hàm nhưng chúng tôi 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 đi lên, chức năng không xác định là những gì .. Ans là: -

    Một chức năng không xác định là chức năng mà trả về kết quả đầu ra khác nhau cho các giá trị đầu vào cùng một lúc khác nhau, như getdate(). Nó luôn luôn trả về giá trị khác nhau bất cứ khi nào nó được chạy.

    Ngoại lệ: -

    Đầu phiên bản của SQL Server trước khi SQL 2000 không cho phép sử dụng getdate() trong hàm do người dùng định nghĩa, nhưng phiên bản năm 2005 và trở đi cho phép chúng ta sử dụng getdate() trong 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 tôi có thể sử dụng nó trong thủ tục được lưu trữ.

  • Chúng ta có thể sử dụng DML (insert, update, delete) tuyên bố trong một lưu trữ thủ tục nhưng chúng tôi không thể sử dụng báo cáo DML trong các chức năng trên bảng về thể chất 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 phải 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ữ.

+0

Cách hoạt động của DML được hỗ trợ trong các hàm MySQL? –

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