Hàm do người dùng xác định (UDF) trong cơ sở dữ liệu chủ


9

Tôi có một chức năng được sử dụng trong hơn một chục cơ sở dữ liệu. Tôi muốn chức năng này có thể truy cập được trong tất cả các cơ sở dữ liệu bằng cách chỉ viết một lần, vì vậy tôi muốn viết hàm trong cơ sở dữ liệu chủ để chức năng của tôi có thể được truy cập dễ dàng.

Có bất kỳ vấn đề trong việc viết hàm do người dùng định nghĩa trong master db không?

Khi lướt Internet, một số gợi ý chuyển đổi chức năng thành chức năng hệ thống. (Sử dụng các EXEC sp_ms_markystemobject 'fn_db_name' ').

Có cần thiết phải chuyển đổi hàm được tạo trong master db thành hàm hệ thống không? Nếu đúng thì tại sao?


Nếu chức năng chỉ đơn giản là thực hiện một thao tác trên dữ liệu được truyền vào và trả về kết quả, sẽ không có vấn đề gì. Tôi đã tìm thấy các vấn đề khi sử dụng một thủ tục được lưu trữ được tạo trong tổng thể tham chiếu các chế độ xem hệ thống như information_schema. Điều này đã được một thời gian dài trước đây. Bất cứ điều gì bạn tạo ra, bạn cần phải kiểm tra đầy đủ.
datagod 04/12/2015

5
Tôi sẽ khuyên không nên đặt nó trong chủ. Tạo một cơ sở dữ liệu tiện ích và đặt nó ở đó. Bạn sẽ cần đảm bảo rằng là một phần của gói DR, bạn có nguồn cho đối tượng trong tổng thể (bạn thường không khôi phục cơ sở dữ liệu hệ thống) và nó đã được cập nhật.
Jonathan Fite 4/12/2015

Chính xác thì chức năng này được cho là làm gì?
Solomon Rutzky 4/12/2015

Câu trả lời:


10

Tôi đồng ý với Jonathan - miễn là chức năng này không phải trả về dữ liệu cục bộ dựa trên bối cảnh cơ sở dữ liệu gọi, đặt chức năng vào cơ sở dữ liệu tiện ích (đây cũng là nơi tôi đặt những thứ như số và bảng lịch, chức năng chia tách, v.v. ):

USE UtilityDB;
GO
CREATE FUNCTION dbo.whatever() RETURNS ...
GO

Bây giờ, trong mọi cơ sở dữ liệu cần truy cập hàm, chỉ cần tạo một từ đồng nghĩa:

CREATE SYNONYM dbo.whatever() FOR UtilityDB.dbo.whatever();

Bằng cách này, mỗi cơ sở dữ liệu vẫn có thể tham chiếu hàm bằng cách sử dụng tên 2 phần đơn giản - và họ không phải biết hoặc quan tâm nơi nó thực sự tồn tại. Và bạn chỉ phải duy trì một bản sao duy nhất của chức năng.

(Và trên thực tế, bạn có thể đặt từ đồng nghĩa vào modelcơ sở dữ liệu để nó được tạo tự động trong cơ sở dữ liệu mới.)

Lý do tôi không thích đưa các đối tượng người dùng vào master- trừ khi chúng thực sự cần phải có sẵn trên toàn cầu và theo ngữ cảnh cho cơ sở dữ liệu cuộc gọi, như phiên bản tùy chỉnh của bạn sp_spaceusedhoặc sp_helpindex- là mọi người không tìm kiếm đối tượng người dùng mastervà chúng ít hơn khám phá ở đó. Chúng cũng làm cho việc di chuyển cơ sở dữ liệu người dùng của bạn ở nơi khác trở nên khó khăn hơn, bởi vì bạn cũng cần phải nhớ những thứ người dùng bạn đặt vào master. Nếu bạn hoàn toàn không sẵn sàng chống lại việc tạo hoặc sử dụng cơ sở dữ liệu tiện ích cho việc này, tôi nghĩ msdblà một lựa chọn thiết thực hơn cho một vị trí trung tâm.


5

Mặc dù tôi đồng ý với @Jonathan và @Aaron rằng bạn nên sử dụng cơ sở dữ liệu "tiện ích" (tôi thậm chí đặt tên cho tôi Utility) và tôi đồng ý với Aaron về việc sử dụng từ đồng nghĩa, tôi muốn thu hút sự chú ý đến lời cảnh báo mà Aaron đã đề cập. quan trọng:

miễn là hàm không được yêu cầu trả về dữ liệu cục bộ dựa trên bối cảnh cơ sở dữ liệu gọi ...

Nghĩa là, nếu bạn làm cần "cơ sở dữ liệu hiện tại" ngữ cảnh (như trái ngược với mã chạy trong cơ sở dữ liệu mà nó thực sự tồn tại, cho dù đó là masterhay Utility), sau đó sử dụng bất cứ điều gì nhưng mastersẽ không làm việc.

Và vì vậy, nếu bạn cần Hàm chạy trong ngữ cảnh của cơ sở dữ liệu được gọi từ đó, thì kế hoạch sử dụng Hàm sẽ không hoạt động vì có mã trong masterDB có thể chạy trong ngữ cảnh cơ sở dữ liệu hiện tại bên ngoài masterchỉ hoạt động cho các thủ tục được lưu trữ, ngay cả khi bạn sử dụng sp_ms_marksystemobjectthủ tục lưu trữ hệ thống không có giấy tờ để đánh dấu Chức năng của bạn là một đối tượng hệ thống. Và trên thực tế, tiền tố tên của Hàm có fn_hoặc thậm chí sp_không cho phép nó được tìm thấy bên ngoài chủ mà không đủ điều kiện tên đối tượng. Và sau đó, ngay cả khi bạn hoàn toàn đủ điều kiện tên, nó vẫn chỉ chạy trong ngữ cảnh của mastercơ sở dữ liệu, ngay cả sau khi được đánh dấu là một đối tượng hệ thống.

Vì vậy, bạn có ba lựa chọn:

  1. Nếu bạn không cần bối cảnh DB hiện tại, thì hãy làm theo lời khuyên của Aaron để sử dụng Utilitycơ sở dữ liệu cho đối tượng và sử dụng từ đồng nghĩa trong cơ sở dữ liệu cần sử dụng Hàm để trỏ đến Utilitycơ sở dữ liệu.
  2. Nếu bạn cần bối cảnh DB hiện tại:

    1. Thay đổi Hàm thành Quy trình được lưu trữ, đổi tên để bắt đầu sp_và chạy sp_ms_marksystemobjectHệ thống được lưu trữ trên đó để đánh dấu nó là Quy trình được lưu trữ của hệ thống (nếu không nó sẽ không phản ánh bối cảnh DB hiện tại cho các truy vấn, mặc dù nó sẽ được xây dựng -in chức năng như thế nào DB_NAME()). Tôi không phải là một fan hâm mộ lớn của phương pháp này, nhưng nó hoạt động.
    2. Sử dụng SQLCLR để tạo một hàm có thể được đặt vào Utilitycơ sở dữ liệu và có tên cơ sở dữ liệu hiện tại (hoặc bất kỳ tên cơ sở dữ liệu nào) được sử dụng để tạo SQL động sẽ là truy vấn được gửi. Tôi đã đăng một ví dụ về cách thực hiện loại này với SQLCLR trong câu trả lời sau, cũng trên DBA.StackExchange:

      Thủ tục lưu trữ trung tâm để thực hiện trong bối cảnh gọi cơ sở dữ liệu

      Bạn cũng có thể sử dụng từ đồng nghĩa trong cách tiếp cận này, và sau đó bạn chỉ cần gọi hàm trong khi truyền vào DB_NAME()để tự động chuyển vào tên cơ sở dữ liệu hiện tại.

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.