2013-04-26 9 views
7

Ho un problema con CROSS APPLY con funzione di tabella parametrizzata. Qui è semplificata esempio di codice pseudo:APPLICAZIONE CROSS con prestazioni limitate della funzione di tabella stimata

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 ... 
  • interno selezionare sul tavolo LOT_OF_ROWS_TABLE sta tornando molte righe.
  • Unire tabelle LOT_OF_ROWS_TABLE e ANOTHER_TABLE restituisce solo una o poche righe.
  • La funzione con valori di tabella richiede molto tempo e quando si chiama un numero di righe la selezione dura molto a lungo.

Il mio problema:

La funzione viene chiamata per tutte le righe restituite dalla LOT_OF_ROWS_TABLE a prescindere dal fatto che i dati saranno limitati quando basta aderire ANOTHER_TABLE.

La selezione deve essere nel formato mostrato - è generata ed in effetti è molto più difficile.

Quando provo a riscriverlo, può essere molto veloce, ma non può essere riscritto così:

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

Mi piacerebbe sapere:

v'è alcuna impostazione o suggerimento o qualcosa che forza selezionare per chiamare la funzione solo per le righe finalmente limitate?

Grazie.

EDIT:

La tabella valutata funzione è molto complessa: http://pastebin.com/w6azRvxR. La selezione di cui stiamo parlando è "configurata dall'utente" e generata: http://pastebin.com/bFbanY2n.

+0

Indicare l'ovvio, forse: Se solo si potesse cambiare l'ordine dei join nel testo della query. Quindi avresti potuto utilizzare l'hint di query FORCE_ORDER. Come viene generato il codice? Non c'è modo di cambiare il comportamento a tale scopo? –

+0

Modifica la funzione 'dbo.HeavyTableValuedFunction (..)' con valore di tabella su più righe in una funzione con valori inline. – RBarryYoung

+0

@RBarryYoung: troppo complesso per riscrivere semplicemente su una funzione inline –

risposta

2

è possibile dividere questa query in 2 parti utilizzano o variabile di tabella o tabella temporanea

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

ora fare il tempo consumando parte che è tabella funzione con valori di destra

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

Grazie, ma non posso farlo, perché 'lor' tabella e croce si applicano devono essere insieme - rappresentano un'unità all'interno della query generata complessa (possono esserci più unità unite) e infine filtrate (in realtà l'altro_table è una variabile di tabella temporanea con alcuni record che rappresentano la restrizione finale). –

1

Credo che questo è ciò che stai cercando.

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

Fondamentalmente si descrive ri-scrittura della query per ottenere un piano generato utilizzando l'ordine corretto di join. Quindi, salvando tale piano e forzando la query esistente (che non viene modificata) per utilizzare il piano che hai salvato.

Il collegamento BOL che ho inserito fornisce anche un esempio specifico di riscrittura della query mettendo i join in un ordine diverso e utilizzando un suggerimento FORCE ORDER. Quindi utilizzare sp_create_plan_guild per prendere il piano dalla query riscritta e utilizzarlo nella query originale.

+0

Sfortunatamente la selezione è "configurata dall'utente" e generata, può unirsi ad altre tabelle - Non posso prevedere il piano. –

0

SI e NO ...è difficile interpretare ciò che stai cercando di ottenere senza dati campione IN e risultati OUT, per confrontare i risultati.

Mi piacerebbe sapere:

C'è qualche impostazione o suggerire o qualcosa che le forze di selezionare per chiamare funzione solo per le righe finalmente ristretti?

Quindi risponderò vostra domanda di cui sopra (3 anni più tardi !!) direttamente, con una dichiarazione diretta:

devi conoscere CTE e la differenza tra CROSS APPLY rispetto al INTERNO ISCRIVITI e perché usare CROSS APPLY nel tuo caso è necessario. "Potresti" prendere il codice nella tua funzione e applicarlo in una singola istruzione SQL usando CTE.

cioè:

Leggi this e this.

In sostanza, qualcosa di simile ...

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 

Applicare I dati di estrapolare la data desiderata una volta, e con CTE, quindi applicare il secondo SQL utilizzando il CROSS APPLY.

Non hai scelta. Non puoi fare ciò che stai cercando di fare in ONE SQL.

Problemi correlati