2013-04-26 30 views
7

Tôi gặp sự cố với CROSS APPLY với chức năng có giá trị bảng được định giá trị. đây được đơn giản hóa ví dụ mã giả:CROSS ÁP DỤNG với hiệu suất hạn chế chức năng bảng có giá trị

SELECT * 
FROM (
    SELECT lor.* 
    FROM LOT_OF_ROWS_TABLE lor 
    WHERE ... 
) AS lor 
CROSS APPLY dbo.HeavyTableValuedFunction(lor.ID) AS htvf 
INNER JOIN ANOTHER_TABLE AS at ON lor.ID = at.ID 
WHERE ... 
  • Nội chọn trên bàn LOT_OF_ROWS_TABLE đang trở lại nhiều hàng.
  • Tham gia các bảng LOT_OF_ROWS_TABLEANOTHER_TABLE chỉ trả lại một hoặc một vài hàng.
  • Chức năng bảng có giá trị rất tốn thời gian và khi gọi cho nhiều hàng thì lựa chọn này kéo dài rất lâu.

Vấn đề của tôi:

Các hàm được gọi cho tất cả các hàng trở về từ LOT_OF_ROWS_TABLE không phụ thuộc vào thực tế là các dữ liệu sẽ bị hạn chế khi chỉ cần tham gia ANOTHER_TABLE.

Lựa chọn phải ở định dạng được hiển thị - nó được tạo ra và trên thực tế nó là nhiều hơn dificult.

Khi tôi cố gắng viết lại nó, nó có thể rất nhanh, nhưng nó không thể được viết lại như thế này:

SELECT * 
FROM (
    SELECT lor.* 
    FROM LOT_OF_ROWS_TABLE lor 
    WHERE ... 
) AS lor 
INNER JOIN ANOTHER_TABLE AS at ON lor.ID = at.ID 
CROSS APPLY dbo.HeavyTableValuedFunction(at.ID) AS htvf 
WHERE ... 

Tôi muốn biết:

Có bất kỳ thiết lập hoặc gợi ý hoặc cái gì đó buộc chọn để gọi chức năng chỉ cho các hàng cuối cùng bị hạn chế?

Cảm ơn bạn.

EDIT:

Bảng giá chức năng là rất phức tạp: http://pastebin.com/w6azRvxR. Lựa chọn mà chúng ta đang nói đến là "cấu hình người dùng" và được tạo: http://pastebin.com/bFbanY2n.

+0

Nói rõ ràng có thể: Nếu chỉ bạn mới có thể thay đổi thứ tự của các kết nối trong văn bản truy vấn. Sau đó, bạn có thể đã sử dụng gợi ý truy vấn FORCE_ORDER. Mã được tạo ra như thế nào? Không có cách nào bạn có thể thay đổi hành vi vào cuối đó? –

+0

Thay đổi hàm băm của bảng 'dbo.HeavyTableValuedFunction (..)' thành hàm Bảng-Giá trị nội tuyến. – RBarryYoung

+0

@RBarryYoung: quá phức tạp để chỉ viết lại một hàm nội tuyến –

Trả lời

2

bạn có thể chia truy vấn này thành 2 phần sử dụng một trong hai biến bảng hoặc bảng temp

SELECT lor.*,at.* into #tempresult 
FROM (
    SELECT lor.* 
    FROM LOT_OF_ROWS_TABLE lor 
    WHERE ... 
) lor 
INNER JOIN ANOTHER_TABLE AS at ON lor.ID = at.ID 
WHERE ... 

bây giờ làm việc tiêu thụ một phần thời gian đó là bảng chức năng có giá trị đúng

SELECT * FROM #tempresult 
CROSS APPLY dbo.HeavyTableValuedFunction(#tempresult.ID) AS htvf 
+0

Cảm ơn bạn, nhưng tôi không thể làm điều này, vì bảng 'lor' và áp dụng chéo phải cùng nhau - chúng đại diện cho một đơn vị trong truy vấn được tạo phức tạp (có thể có nhiều đơn vị hơn) và sau đó lọc (trong thực tế, another_table là biến bảng tạm thời với một số bản ghi đại diện cho hạn chế cuối cùng). –

1

Tôi tin rằng đây là những gì bạn đang tìm kiếm.

Plan Forcing Scenario: Create a Plan Guide to Force a Plan Obtained from a Rewritten Query

Về cơ bản nó mô tả lại cách viết các truy vấn để có được một kế hoạch tạo ra bằng cách sử dụng theo đúng thứ tự của tham gia. Sau đó, tiết kiệm kế hoạch đó và buộc truy vấn hiện tại của bạn (không được thay đổi) để sử dụng gói bạn đã lưu.

Liên kết BOL mà tôi đưa vào thậm chí đưa ra một ví dụ cụ thể về việc viết lại truy vấn đưa các kết nối theo thứ tự khác và sử dụng gợi ý FORCE ORDER. Sau đó, sử dụng sp_create_plan_guild để lấy kế hoạch từ truy vấn được viết lại và sử dụng nó trên truy vấn ban đầu.

+0

Thật không may là lựa chọn là "người dùng cấu hình" và tạo ra, nó có thể tham gia nhiều bảng khác - Tôi không thể dự đoán kế hoạch. –

0

CÓ và KHÔNG ...thật khó để diễn giải những gì bạn đang cố gắng đạt được mà không có dữ liệu mẫu IN và kết quả OUT, để so sánh kết quả.

Tôi muốn biết:

Có bất kỳ thiết lập hoặc gợi ý hoặc cái gì đó lực chọn để gọi chức năng chỉ cho các hàng cuối cùng bị hạn chế?

Vì vậy, tôi sẽ trả lời câu hỏi của bạn ở trên (3 năm sau !!) trực tiếp, với một tuyên bố trực tiếp:

Bạn cần phải tìm hiểu về CTE và sự khác biệt giữa CHÉO ÁP DỤNG so với INNER THAM GIA và tại sao sử dụng CROSS APPLY trong trường hợp của bạn là cần thiết. Bạn "có thể" lấy mã trong hàm của bạn và áp dụng nó vào một câu lệnh SQL duy nhất bằng cách sử dụng CTE.

ví dụ:

đọc thisthis.

Về cơ bản, một cái gì đó như thế này ...

WITH t2o AS 
     (
     SELECT t2.*, ROW_NUMBER() OVER (PARTITION BY t1_id ORDER BY rank) AS rn 
     FROM t2 
     ) 
SELECT t1.*, t2o.* 
FROM t1 
INNER JOIN 
     t2o 
ON  t2o.t1_id = t1.id 
     AND t2o.rn <= 3 

Áp dụng truy vấn của bạn áp dụng rộng rãi ngày bạn muốn một lần, và sử dụng CTE, sau đó áp dụng SQL thứ hai của bạn sử dụng mệnh đề CROSS ÁP DỤNG.

Bạn không có lựa chọn nào khác. Bạn không thể làm những gì bạn đang cố gắng làm trong ONE SQL.

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