Funções vs procedimentos armazenados

88

Digamos que eu tenha que implementar um trecho de código T-SQL que deve retornar uma tabela como resultado. Posso implementar uma função com valor de tabela ou então um procedimento armazenado que retorna um conjunto de linhas. O que devo usar?

Resumindo, o que eu quero saber é:

Quais são as principais diferenças entre funções e procedimentos armazenados? Que considerações devo levar em consideração para usar um ou outro?

Auron
fonte
1
Esta parece ser a resposta perfeita: stackoverflow.com/a/1179778/365188
Ozair Kafray

Respostas:

51

Se você provavelmente deseja combinar o resultado desse trecho de código com outras tabelas, obviamente uma função com valor de tabela permitirá que você componha os resultados em uma única instrução SELECT.

Geralmente, há uma hierarquia (View <TV Function <Stored Proc). Você pode fazer mais em cada um, mas a capacidade de compor as saídas e de o otimizador realmente se envolver diminui à medida que a funcionalidade aumenta.

Portanto, use o que lhe permitir, no mínimo, expressar o resultado desejado.

Damien_The_Unbeliever
fonte
50

As funções devem ser determinísticas e não podem ser usadas para fazer alterações no banco de dados, enquanto os procedimentos armazenados permitem que você faça inserções e atualizações, etc.

Você deve limitar o uso de funções, pois elas representam um grande problema de escalabilidade para consultas grandes e complexas. Eles se tornam uma espécie de "caixa preta" para o otimizador de consulta, e você verá enormes diferenças de desempenho entre usar funções e simplesmente inserir o código em uma consulta.

Mas eles são definitivamente úteis para retornos com valor de tabela em casos muito específicos.

Se você precisar analisar uma lista delimitada por vírgulas, para simular a passagem de um array para um procedimento, uma função pode transformar a lista em uma tabela para você. Esta é uma prática comum com o Sql Server 2005, uma vez que não podemos passar tabelas para stored procedures (podemos com 2008).

Eric Z Beard
fonte
1
Mas você PODE enviar XML para um procedimento armazenado: stackoverflow.com/questions/144550/…
cllpse
2
Errado, a maioria das funções do servidor SQL não são determinísticas, como getdate no servidor MS-SQL. Apenas funções ODBC são funções canônicas (= muito mais rápido + indexável) ... Mas você está muito correto, deve-se limitar o uso de funções em consultas tanto quanto possível por motivos de desempenho.
Stefan Steiger
45

Dos documentos :

Se um procedimento armazenado atender aos seguintes critérios, é um bom candidato para ser reescrito como uma função com valor de tabela:

  • A lógica pode ser expressa em uma única instrução SELECT, mas é um procedimento armazenado, em vez de uma visualização, apenas devido à necessidade de parâmetros.

  • O procedimento armazenado não executa operações de atualização, exceto para variáveis ​​de tabela.

  • Não há necessidade de instruções EXECUTE dinâmicas.

  • O procedimento armazenado retorna um conjunto de resultados.

  • O objetivo principal do procedimento armazenado é construir resultados intermediários que devem ser carregados em uma tabela temporária, que é então consultada em uma instrução SELECT.

Christoffer Lette
fonte
12

Vou escrever algumas diferenças interessantes entre procedimentos armazenados e funções.

  • Podemos usar funções em consultas selecionadas, mas não podemos usar procedimentos armazenados em consultas selecionadas.
  • Não podemos usar funções não determinísticas em funções, mas podemos usar funções não determinísticas em procedimentos armazenados. Agora surge a pergunta, o que é função não determinística .. Resp é: -

    Uma função não determinística é aquela função que retorna diferentes saídas para os mesmos valores de entrada em tempos diferentes, como getdate (). Ele sempre retorna um valor diferente sempre que é executado.

    Exceção:-

    Versões anteriores do sql server anteriores ao sql 2000 não permitem o uso da função getdate () em funções definidas pelo usuário, mas a versão 2005 e posteriores nos permitem usar a função getdate () dentro de uma função definida pelo usuário.

    Newid () é outro exemplo de função não determinística, mas não pode ser usado em funções definidas pelo usuário, mas podemos usá-lo em procedimento armazenado.

  • Podemos usar instruções DML (inserir, atualizar, excluir) dentro de um procedimento armazenado, mas não podemos usar instruções DML em funções em tabelas físicas ou tabelas permanentes. Se quisermos fazer operação DML em funções, podemos fazê-lo sobre variáveis ​​de tabela, não em tabelas permanentes.

  • Não podemos usar o tratamento de erros dentro da função, mas podemos fazer o tratamento de erros em procedimentos armazenados.

Neeraj Kumar Yadav
fonte
Como as operações DML são suportadas nas funções MySQL?
Joey Pinto
@JoeyPinto. Porque myNONsql não é reclamação de SQL. Claro, tem extras, mas não o básico.
PerformanceDBA
8
  1. O procedimento pode retornar zero ou n valores, enquanto a função pode retornar um valor que é obrigatório.

  2. Os procedimentos podem ter parâmetros de entrada / saída, enquanto as funções podem ter apenas parâmetros de entrada.

  3. O procedimento permite selecionar, bem como a instrução DML nele, enquanto a função permite apenas selecionar a instrução nele.

  4. As funções podem ser chamadas a partir do procedimento, enquanto os procedimentos não podem ser chamados a partir da função.

  5. A exceção pode ser tratada pelo bloco try-catch em um procedimento, enquanto o bloco try-catch não pode ser usado em uma função.

  6. Podemos ir para o gerenciamento de transações no procedimento, enquanto não podemos ir para a função.

  7. Os procedimentos não podem ser utilizados em uma instrução select, enquanto a função pode ser incorporada em uma instrução select.

  8. UDF (função definida pelo usuário) pode ser usada nas instruções SQL em qualquer lugar na seção WHERE/ HAVING/ SELECT, enquanto os procedimentos armazenados não podem ser.

  9. UDFs que retornam tabelas podem ser tratadas como outro conjunto de linhas. Isso pode ser usado em JOINs com outras tabelas.

  10. UDFs embutidos podem ser vistos como visualizações que aceitam parâmetros e podem ser usados ​​em se JOINoutras operações de conjunto de linhas.

nathan1138
fonte
6

Se você tem uma função, você pode usá-la como parte de sua instrução SQL, por exemplo

SELECT function_name(field1) FROM table

Não funciona dessa maneira para procedimentos armazenados.

Ilya Kochetov
fonte
1
Acho que ele estava falando sobre funções que retornam valores de tabelas.
wcm
1
Bem, estou falando em geral. Mas, para meu caso específico, agora estou entre um procedimento armazenado ou uma função com valor de tabela.
Auron,
5

Eu executei alguns testes com um bit de lógica de longa execução, com o mesmo pedaço de código (uma instrução SELECT longa) em execução em uma Função com valor de tabela e em um procedimento armazenado, e um EXEC / SELECT direto, e cada um executado de forma idêntica.

Na minha opinião, sempre use uma função com valor de tabela em vez de um procedimento armazenado para retornar um conjunto de resultados, pois torna a lógica muito mais fácil e legível em consultas que subsequentemente se unem a eles e permite que você reutilize a mesma lógica. Para evitar um impacto excessivo no desempenho, costumo usar parâmetros "opcionais" (ou seja, você pode passar NULL para eles) para permitir que a função retorne o conjunto de resultados mais rápido, por exemplo:

CREATE FUNCTION dbo.getSitePermissions(@RegionID int, @optPersonID int, optSiteID int)
AS
RETURN 
    SELECT DISTINCT SiteID, PersonID
    FROM dbo.SiteViewPermissions
    WHERE (@optPersonID IS NULL OR @optPersonID = PersonID)
    AND (@optSiteID IS NULL OR @optSiteID = SiteID)
    AND @RegionID = RegionID

Desta forma, você pode usar esta função para muitas situações diferentes e não terá um grande impacto no desempenho. Acredito que isso seja mais eficiente do que filtrar depois:

SELECT * FROM dbo.getSitePermissions(@RegionID) WHERE SiteID = 1

Usei essa técnica em várias funções, às vezes com uma longa lista de parâmetros "opcionais" desse tipo.

Paul Grimshaw
fonte
4

Eu pessoalmente uso funções com valor de tabela quando tudo que estou retornando é uma única tabela sem efeitos. Basicamente, eu os trato como visualizações parametrizadas.

Se eu precisar que vários conjuntos de registros sejam retornados ou se houver valores atualizados nas tabelas, eu uso um procedimento armazenado.

Meus 2 centavos

wcm
fonte
4

Como mencionado acima, as funções são mais legíveis / combináveis ​​/ autodocumentáveis, mas têm menos desempenho em geral, e podem ter muito menos desempenho se você se empolgar com elas em junções, como

SELECT *
FROM dbo.tvfVeryLargeResultset1(@myVar1) tvf1
INNER JOIN dbo.tvfVeryLargeResultset1(@myVar2) tvf2
    ON (tvf1.JoinId = tvf2.JoinId)

Muitas vezes, você só precisa aceitar a redundância de código que um tvf poderia eliminar (a um custo de desempenho inaceitável).

Um outro ponto que ainda não vi mencionado é que você não pode usar tabelas temporárias de alteração de estado do banco de dados dentro de um tvf com várias instruções. O mecanismo mais funcionalmente equivalente a uma tabela temporária é a não mudança de estado, na variável da tabela de memória, e para grandes conjuntos de dados, uma tabela temporária provavelmente terá mais desempenho do que uma variável de tabela. (Outras alternativas incluem tabelas dinâmicas e expressões de valor de tabela comuns, mas em algum nível de complexidade, essas deixam de ser uma boa opção IMO.)

6eorge Jetson
fonte
1

Gostaria de testar o desempenho de ambos. É provável que a abordagem sp ou uma tabela derivada seja significativamente mais rápida do que uma função e, nesse caso, essa abordagem deve ser usada. Em geral, evito funções porque podem ser um grande obstáculo.

HLGEM
fonte
1

Depende :) Se você quiser usar o resultado com valor de tabela em outro procedimento, é melhor usar uma função TableValued. Se os resultados forem para um cliente, o procedimento armazenado é geralmente o melhor caminho a seguir.

edosoft
fonte
-1

Stored procedures são queries pré-compiladas que executam mais rapidamente e economizam das injeções de sql. Eles podem retornar 0 ou N valores. Podemos realizar operações DML dentro dos procedimentos armazenados. Podemos usar funções dentro dos procedimentos e podemos usar funções na consulta selecionada. Funções são usadas para retornar qualquer valor e operações DML não possíveis em funções. as funções são de dois tipos escalares e com valor de tabela. função escalar retorna um único valor, função com valor de tabela usada para retornar linhas de tabelas.

Harish Madaan
fonte
Esta é uma pergunta muito antiga com um grande número de respostas, muitas delas (incluindo a resposta aceita) são altamente votadas. Antes de adicionar outra resposta a esse tópico, você deve se perguntar: "O que todas essas respostas existentes não têm que me obrigam a escrever outra?"
APC