2010-12-15 33 views
8

OK vì vậy tôi đã đọc toàn bộ các bài viết đề xuất các hàm giá trị bảng và áp dụng chéo cho hiệu năng tốt hơn so với udf vô hướng. Tôi muốn viết chức năng của mình theo cả hai cách và sau đó kiểm tra xem cái nào tốt hơn - nhưng tôi không thể tìm ra cái mà tôi phải sử dụng/tìm hiểu xem đó là lựa chọn nào tốt hơn.Kiểm tra hiệu năng của hàm vô hướng so với bảng trong máy chủ sql

Tôi đang sử dụng SQL Server 2005. Tôi đã thử chạy kế hoạch thực hiện ước tính, kế hoạch thực hiện thực tế và phân tích truy vấn trong trình cố vấn điều chỉnh công cụ cơ sở dữ liệu và tôi không biết nó đang cố gắng nói với tôi.

Sử dụng showplan_all bật/tắt có vẻ như chức năng dựa trên bảng sẽ sử dụng nhiều CPU 1.157e-06 hơn 8.3e-05 nhưng hàm bảng có tổng chi phí subtree là 0.000830157 so với 0,01983356.

Chi phí truy vấn của hàm có giá trị bảng cũng dường như có chi phí cao hơn giá trị vô hướng. Mặc dù tôi nghĩ rằng nó được cho là lựa chọn tốt hơn.

Vì vậy, trong khi tôi muốn chứng minh bản thân mình cái nào mang lại hiệu suất tốt hơn - Tôi chỉ không chắc chắn nên tìm những gì trong những công cụ này - vì vậy mọi đề xuất sẽ được đánh giá cao!

Tôi cần có giá trị năm học (dựa trên phạm vi ngày được đặt trong cơ sở dữ liệu) dựa trên ngày lịch để nội dung hàm bên dưới - vì vậy chỉ cho dù tôi sử dụng vô hướng hoặc dựa trên bảng. Năm nay cung cấp các truy vấn khác ..

CREATE FUNCTION fn_AcademicYear 
(
    -- Add the parameters for the function here 
    @StartDate DateTime 
) 
RETURNS 
@AcademicYear TABLE 
(
    AcademicYear int 
) 
AS 
BEGIN 

DECLARE @YearOffset int, @AcademicStartDate DateTime 

    -- Lookup Academic Year Starting Date 
    SELECT @AcademicStartDate = CONVERT(DateTime,[Value]) 
    FROM dbo.SystemSetting 
    WHERE [Key] = 'AcademicYear.StartDate' 

    SET @YearOffset = DATEPART(YYYY,@StartDate) - DATEPART(YYYY,@AcademicStartDate); 
    -- try setting academic looking start date to year of the date passed in 
    SET @AcademicStartDate = DATEADD(YYYY, @YearOffset, @AcademicStartDate); 

    IF @StartDate < @AcademicStartDate 
    BEGIN 
     SET @AcademicStartDate = DATEADD(YYYY, @YearOffset-1, @AcademicStartDate); 
    END 

     INSERT @AcademicYear 
     SELECT YEAR(@AcademicStartDate) 

    RETURN 

Cảm ơn !!

+2

Chỉ vì tò mò - bạn có thực sự thấy rằng 'YYYY' dễ đọc hơn, ví dụ:' Year'? –

+0

Tôi đã không thực sự nghĩ về nó .. và lấy cú pháp đó từ chức năng của người khác :) Nhưng có Năm sẽ dễ đọc hơn. – Jen

Trả lời

16

Bạn có thể không thấy lợi ích hiệu suất mà bạn mong đợi vì hàm có giá trị của bảng là đa chức năng chứ không phải trực tuyến. Các TVF đa chức năng phải được thực hiện giống như UDF vô hướng - một lần cho mỗi hàng - vì vậy có rất ít lợi ích.

Tiếp theo ví dụ trong this article by Itzik Ben-Gan (mà thảo luận về những lợi ích của in-line TVFs), thiết lập các thử nghiệm sau đây:

Tạo một bảng số với 1 triệu hàng:

SET NOCOUNT ON; 
IF OBJECT_ID('dbo.T1') IS NOT NULL DROP TABLE T1; 
GO 

WITH 
    L0 AS (SELECT 0 AS c UNION ALL SELECT 0), 
    L1 AS (SELECT 0 AS c FROM L0 AS A CROSS JOIN L0 AS B), 
    L2 AS (SELECT 0 AS c FROM L1 AS A CROSS JOIN L1 AS B), 
    L3 AS (SELECT 0 AS c FROM L2 AS A CROSS JOIN L2 AS B), 
    L4 AS (SELECT 0 AS c FROM L3 AS A CROSS JOIN L3 AS B), 
    L5 AS (SELECT 0 AS c FROM L4 AS A CROSS JOIN L4 AS B), 
    Nums AS (SELECT ROW_NUMBER() OVER(ORDER BY (SELECT 0)) AS n FROM L5) 
SELECT n INTO dbo.T1 FROM Nums WHERE n <= 1000000; 

Chạy một triệu thực hiện TVF của bạn bằng cách sử dụng mã sau:

set statistics time on 
SELECT n,DATEADD(HOUR,n,'1900-01-01'),AY.AcademicYear 
FROM T1 
CROSS APPLY dbo.fn_AcademicYear(DATEADD(HOUR,n,'1900-01-01')) AS AY 
set statistics time off 

Trên hệ thống của tôi, điều này cho thấy trung bình 83 giây thời gian trôi qua cho ba lần thực hiện, runn ing DBCC dropcleanbuffers giữa mỗi lần thực thi.

Nếu bạn thực hiện một thử nghiệm tương tự cho hàm vô hướng có giá trị của mình, bạn nên có ý tưởng rõ ràng hơn về hiệu suất so sánh.

Bài kiểm tra cũng cho thấy có vẻ như là lỗi trong chức năng của bạn. Nếu AcademicYear.StartDate được đặt thành '2010-09-01', Năm học trở lại cho đầu vào là '1900-01-01' là 1789, có vẻ như năm 1899 được mong đợi.

Để có được hiệu suất tốt nhất, bạn cần phải chuyển đổi các TVF là in-line - Tôi đã đưa ra những điều sau đây, mà tôi tin rằng sửa chữa các lỗi:

CREATE FUNCTION fn_AcademicYear2 
(
    @StartDate DATETIME 
) 
RETURNS TABLE 
AS 
RETURN 
(
    -- Lookup Academic Year Starting Date 
    WITH dtCTE 
    AS 
    (
     SELECT CONVERT(DATETIME,[Value]) AS dt 
     FROM dbo.SystemSetting 
     WHERE [KEY] = 'AcademicYear.StartDate' 
    ) 
    SELECT CASE WHEN @StartDate >= DATEADD(YEAR,DATEDIFF(YEAR,dt,@StartDate),dt) 
       THEN YEAR(@StartDate) 
       ELSE YEAR(DATEADD(YEAR,DATEDIFF(YEAR,dt,@StartDate) - 1,dt)) 
      END AS AcademicYear 
    FROM dtCTE 
) 
GO 

này có trung bình trôi qua thời gian 8,9 giây trên ba lần chạy - nhanh hơn gần gấp mười lần.

Điều khác cần xem xét là lợi ích hiệu suất từ ​​việc sử dụng TVF sẽ không đáng kể trừ khi bạn áp dụng nó cho nhiều hàng, như trong bài kiểm tra này. Nếu bạn đang sử dụng nó trên một giá trị tại một thời điểm, bạn sẽ không nhìn thấy rất nhiều benfit trừ khi bạn có hàng ngàn trường hợp của hàm thực thi song song.

+0

Cảm ơn câu trả lời thực sự chi tiết và để cải thiện chức năng của tôi !! :) – Jen

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