Na maioria dos casos, é melhor evitar funções de valor escalar que referenciam tabelas porque (como outros disseram) elas são basicamente caixas pretas que precisam ser executadas uma vez para cada linha e não podem ser otimizadas pelo mecanismo de plano de consulta. Portanto, eles tendem a escalar linearmente mesmo se as tabelas associadas tiverem índices.
Você pode querer considerar o uso de uma função com valor de tabela embutida, pois elas são avaliadas em linha com a consulta e podem ser otimizadas. Você obtém o encapsulamento desejado, mas o desempenho de colar as expressões diretamente na instrução select.
Como efeito colateral de serem embutidos, eles não podem conter nenhum código de procedimento (não declare @variable; set @variable =..; return). No entanto, eles podem retornar várias linhas e colunas.
Você poderia reescrever suas funções mais ou menos assim:
create function usf_GIS_GET_LAT(
@City varchar (30),
@State char (2)
)
returns table
as return (
select top 1 lat
from GIS_Location with (nolock)
where [State] = @State
and [City] = @City
);
GO
create function usf_GIS_GET_LON (
@City varchar (30),
@State char (2)
)
returns table
as return (
select top 1 LON
from GIS_Location with (nolock)
where [State] = @State
and [City] = @City
);
A sintaxe para usá-los também é um pouco diferente:
select
Lat.Lat,
Lon.Lon
from
Address_Location with (nolock)
cross apply dbo.usf_GIS_GET_LAT(City,[State]) AS Lat
cross apply dbo.usf_GIS_GET_LON(City,[State]) AS Lon
WHERE
ID IN (SELECT TOP 100 ID FROM Address_Location WITH(NOLOCK) ORDER BY ID DESC)