2013-04-26 25 views
7

Mam problem z CROSS APPLY z parametryzowaną funkcją wycenianą w tabeli. Tutaj jest uproszczony przykład kodu pseudo:CROSS APPLY z tabelą o ograniczonej wydajności funkcji

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 ... 
  • Wewnętrzna wybrać na stół LOT_OF_ROWS_TABLE powraca wiele wierszy.
  • Łączenie tabel LOT_OF_ROWS_TABLE i ANOTHER_TABLE zwraca tylko jeden lub kilka wierszy.
  • Funkcja wyceniana za pomocą tabeli jest bardzo czasochłonna i podczas wywoływania wielu wierszy wybór trwa bardzo długo.

Mój problem:

Funkcja jest wywoływana dla wszystkich wierszy zwracanych z LOT_OF_ROWS_TABLE niezależnie od faktu, że dane zostaną ograniczone, gdy tylko przyłączyć ANOTHER_TABLE.

Wybór musi być w przedstawionym formacie - jest generowany, a w rzeczywistości jest znacznie trudniejszy.

Kiedy próbuję go przepisać, to może być bardzo szybka, ale to nie może być zapisane tak:

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 ... 

Chciałbym wiedzieć:

Czy istnieje ustawienie lub podpowiedź czy coś, co zmusza funkcję select do wywołania tylko dla ostatecznie ograniczonych wierszy?

Dziękuję.

Edycja:

Tabela cenione funkcja jest bardzo złożona: http://pastebin.com/w6azRvxR. Wybrany przez nas parametr to "skonfigurowany przez użytkownika" i wygenerowany: http://pastebin.com/bFbanY2n.

+0

Stwierdzenie oczywiste: być może: gdybyś mógł zmienić kolejność złączeń w tekście zapytania. Wtedy mógłbyś użyć wskazówki zapytania FORCE_ORDER. W jaki sposób generowany jest kod? Czy nie można zmienić zachowania w tym celu? –

+0

Zmień wieloliniową funkcję wielowierszową o nazwie "dbo.HeavyTableValuedFunction (..)" na wbudowaną funkcję wartości tabeli. – RBarryYoung

+0

@RBarryYoung: zbyt skomplikowane, aby po prostu przepisać na funkcję inline –

Odpowiedz

2

można podzielić tę kwerendę do 2 części użyć zmiennej tabeli lub tabeli 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 ... 

teraz zrobić czasochłonne część, która jest funkcja wycenione tabela prawo

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

Dziękuję, ale nie mogę tego zrobić, ponieważ "lor" tabela i krzyż muszą być razem - reprezentują one jedną jednostkę w złożonym wygenerowanym zapytaniu (może być więcej połączonych jednostek), a następnie w końcu filtrowane (w rzeczywistości another_table jest zmienną tabeli tymczasowej z pewnymi rekordami, które reprezentują ostateczne ograniczenie). –

1

Wierzę, że to, co szukasz.

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

zasadzie to opisuje ponownego pisania zapytania, aby uzyskać wygenerowany planu stosując właściwą kolejność złączeń. Następnie oszczędzając ten plan i wymuszając istniejące zapytanie (które się nie zmienia), aby użyć planu, który został zapisany.

Łącze BOL, które umieściłem, wręcza konkretny przykład ponownego napisania kwerendy umieszczającej łączenia w innej kolejności i za pomocą podpowiedzi FORCE ORDER. Następnie użyj sp_create_plan_guild, aby pobrać plan z ponownie napisanego zapytania i użyć go w pierwotnym zapytaniu.

+0

Niestety, wybrany jest "skonfigurowany przez użytkownika" i wygenerowany, może dołączyć do innych tabel - nie mogę przewidzieć planu. –

0

TAK i NIE ...Trudno wyobrazić sobie, co próbujesz osiągnąć, bez przykładowych danych i wyniku OUT, w celu porównania wyników.

Chciałbym wiedzieć:

Czy istnieje ustawienie lub podpowiedź czy coś, że siły wybrać zadzwonić funkcję tylko na końcu ograniczonych wierszy?

Więc będę odpowiedzieć na pytanie powyżej (3 lata później !!) bezpośrednio, z bezpośrednim stwierdzeniem:

Musisz dowiedzieć się o CTE, a różnica między CROSS APPLY porównaniu do INNER JOIN i dlaczego użycie CROSS APPLY w twoim przypadku jest konieczne . Możesz "wziąć" kod w swojej funkcji i zastosować go w pojedynczej instrukcji SQL za pomocą metody CTE.

tj:

Czytaj this i this.

Zasadniczo coś takiego ...

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 

Zastosuj zapytanie do ekstrapolacji datę chcesz raz, i za pomocą CTE, a następnie zastosować drugą SQL przy użyciu CROSS APPLY.

Nie masz wyboru. Nie możesz zrobić tego, co chcesz zrobić w JEDNYM SQL.