O problema me deixou louco por alguns dias, posso ter encontrado minha resposta, mas preciso de uma confirmação e verificar uma eventual solução fácil.
Quando um procedimento armazenado usa algumas funções definidas pelo usuário, os planos UDF são mesclados no plano principal e tudo é otimizado ou eles são chamados diretamente todas as vezes?
E suponha que isso não aconteça, existe uma maneira de forçar o SQL Server a fazer isso para um SP específico?
Se eu entendi a pergunta corretamente, deve depender do tipo de função. Funções com valor de tabela inline têm suas definições substituídas em consultas de referência, assim como acontece com visualizações. Isto é o que se entende por "inline", e porque eles não são módulos verdadeiros que podem ser assinados, entre outras diferenças com os outros tipos de função.
Funções com valor de tabela de várias instruções e funções escalares definidas pelo usuário são módulos completamente independentes que são executados separadamente e têm seus próprios planos.
Esse comportamento não deve ter nada a ver com eles sendo referenciados em um procedimento armazenado ou em uma consulta ad hoc.
Agora, se as UDFs são ou não chamadas todas as vezes, isso depende do tipo de UDF:
IsDeterministic=true;
(éfalse
por padrão) e não estiverem fazendo nenhum acesso a dados, não impedem planos paralelos e devem poder ter seus valores de retorno armazenados em cache (por execução de consulta, suponho).É por isso que, sempre que possível, é melhor converter UDFs T-SQL em TVFs T-SQL Inline.