2009-11-12 5 views
5

J'ai une requête comme suit:appel de fonction dans la clause where

SELECT * FROM Members (NOLOCK) 
WHERE Phone= dbo.FormatPhone(@Phone) 

Je comprends maintenant ici que la mise en forme doit être appliquée sur la variable sur la colonne. Mais devrais-je l'appliquer sur une variable pour l'assigner à une autre variable locale puis l'utiliser (comme ci-dessous).

Set @SomeVar = dbo.FormatPhone(@Phone) 

SELECT * 
    FROM Members (NOLOCK) WHERE Phone= @SomeVar 

Quelle est la meilleure façon ou les deux sont bonnes?

EDIT: Et comment est la première requête différente de

SELECT * FROM Members (NOLOCK) 
WHERE dbo.FormatPhone(Phone) = @Phone 

Répondre

7

Comme d'habitude avec SQL, la requête est largement non pertinente sans savoir que le schéma réel est utilisé.

Avez-vous un indice sur Members.Phone? Si non, cela ne fait aucune différence sur la façon dont vous écrivez la requête, ils vont tous scanner la table entière et faire la même chose (c'est-à-dire fonctionner mal). Si vous ont un indice alors la façon dont vous écrivez la requête fait toute la différence:

SELECT * FROM Members WHERE Phone= @Phone; 
SELECT * FROM Members WHERE Phone= dbo.FormatPhone(@Phone); 
SELECT * FROM Members WHERE dbo.FormatPhone(Phone)[email protected]; 

la première requête est garantie optimale, cherchera le téléphone sur l'indice.
La deuxième requête dépend des caractéristiques du dbo.FormatPhone. Il peut ou peut ne pas utiliser une recherche optimale.
Dernière requête est garantie d'être mauvaise. Va scanner la table.

Aussi, j'ai enlevé l'indice NOLOCK, il semble que le thème du jour ... Voir syntax for nolock in sql. NOLOCK est toujours la mauvaise réponse. Utilisez l'isolation d'instantané.

+0

Je suis passé par la poste et il parle de ne pas utiliser NOLOCK avec des instructions Update/Insert. –

+0

Voulez-vous dire utiliser avec (nolock) au lieu de NOLOCK? –

+0

Avez-vous l'intention de lire des données non-officielles ou avez-vous ajouté NOLOCK comme solution de contournement pour les problèmes de concurence? –

4

Le second est certainement préféré. Le premier évaluera la fonction pour chaque ligne de la table, tandis que l'autre ne fera le calcul qu'une seule fois.

+0

En outre, la première option ne sera probablement pas en mesure d'utiliser un index. – Kuberchaun

+0

L'évaluation de fonction pour chaque rangée sera là si nous appliquons la fonction sur la colonne ou la variable de table? Ou les deux façons sont les mêmes? –

+0

Non, si vous effectuez le calcul à l'avance, vous passez essentiellement la requête à une constante. –

5

Vous aurez certainement une meilleure prévisibilité si vous affectez d'abord une variable, beaucoup de dépendances dans l'optimiseur autour du déterminisme par rapport au non-déterminisme.

0
SELECT * FROM Members (NOLOCK) 
WHERE Phone= dbo.FormatPhone(@Phone) 

dans la requête ci-dessus, function dbo.FormatPhone sera exécuté pour chaque ligne dans le tableau Members.

lorsque le deuxième requête

Set @SomeVar = dbo.FormatPhone(@Phone) 

SELECT * 
FROM Members (NOLOCK) WHERE Phone= @SomeVar 

il va exécuter la fonction qu'une seule fois. Donc, je pense que la deuxième option sera plus rapide au cas où vous auriez de grandes données dans la table des membres.

+0

Merci vrunda.Je reçois différentes réponses et opinions ici, mais je ne sais pas croire que la fonction s'exécutera pour chaque ligne de la première requête. Avez-vous des références qui le prouvent? –