J'ai un problème avec CROSS APPLY
avec la fonction de valeur de table paramétrée. Voici un exemple de pseudo-code simplifié:
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 ...
LOT_OF_ROWS_TABLE
renvoie plusieurs lignes.LOT_OF_ROWS_TABLE
et ANOTHER_TABLE
ne renvoie qu'une ou plusieurs lignes. Mon problème:
La fonction est appelée pour toutes les lignes renvoyées par LOT_OF_ROWS_TABLE
, indépendamment du fait que les données seront limitées lorsque vous joindrez simplement ANOTHER_TABLE
.
La sélection doit être dans le format indiqué - elle est générée et en fait, elle est beaucoup plus difficile.
Quand j'essaye de le réécrire, ça peut être très rapide, mais ça ne peut pas être réécrit comme ça:
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 ...
J'aimerais savoir:
Existe-t-il un paramètre ou un indice ou quelque chose qui oblige select à appeler la fonction uniquement pour les lignes finalement restreintes?
Je vous remercie.
EDIT:
La fonction table value est très complexe: http://Pastebin.com/w6azRvxR . La sélection dont nous parlons est "configurée par l'utilisateur" et générée: http://Pastebin.com/bFbanY2n .
vous pouvez diviser cette requête en 2 parties utilisent soit une variable de table, soit une table temporaire
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 ...
maintenant faire la partie qui prend du temps qui est la fonction de valeur de table droite
SELECT * FROM #tempresult
CROSS APPLY dbo.HeavyTableValuedFunction(#tempresult.ID) AS htvf
Je crois que c'est ce que vous recherchez.
En gros, il décrit la réécriture de la requête pour obtenir un plan généré en utilisant le bon ordre de jointure. Enregistrez ensuite ce plan et forcez votre requête existante (qui ne sera pas modifiée) à utiliser le plan que vous avez enregistré.
Le lien BOL que je mets donne même un exemple spécifique de réécriture de la requête en plaçant les jointures dans un ordre différent et en utilisant un indice FORCE ORDER
. Ensuite, utilisez sp_create_plan_guild
pour extraire le plan de la requête réécrite et l'utiliser pour la requête d'origine.
OUI et NON ... il est difficile d'interpréter ce que vous essayez d'accomplir sans échantillon de données IN et result OUT, pour comparer les résultats.
J'aimerais savoir:
Existe-t-il un paramètre ou un indice ou quelque chose qui oblige la sélection à appeler la fonction Uniquement pour les lignes finalement restreintes?
Je vais donc répondre à votre question ci-dessus (3 ans plus tard !!) directement, avec une déclaration directe:
Vous devez vous renseigner sur le CTE et sur la différence entre CROSS APPLY Et INNER JOIN, et pourquoi utiliser CROSS APPLY dans votre cas est Nécessaire. Vous "pourriez" prendre le code dans votre fonction et l'appliquer Dans une seule instruction SQL utilisant CTE.
c'est à dire:
Essentiellement, quelque chose comme ça ...
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
Appliquez votre requête pour extrapoler la date souhaitée ONCE, puis utilisez CTE, puis appliquez votre deuxième SQL à l’aide de CROSS APPLY.
Tu n'as pas le choix. Vous ne pouvez pas faire ce que vous essayez de faire dans ONE SQL.