Recentemente, notei que o aplicativo da minha empresa estava usando AddWithValue
para passar valores de parâmetros para consultas dinâmicas e parametrizadas. Exemplo:
cmd.Parameters.AddWithValue("@VehicleId", Vehicles.VehicleId);
No banco de dados, o tipo de dados para VehicleID
é INT
.
Pelo que entendi, como AddWithValue (que está obsoleto) não especifica o tipo/comprimento de dados, este '@VehicleID' é convertido e potencialmente convertido incorretamente. Essa conversão afeta o desempenho do SQL Server no caso de um 'INT'?
Isso causaria problemas além da poluição do cache do plano? Há um impacto no desempenho causado pela conversão?
Eu recomendo sempre usar o método que permite definir explicitamente o tipo de dados e a precisão. Sim, isso é mais trabalhoso, tanto no início quanto se o tipo de dados no banco de dados mudar (o que é comum quando, digamos, uma
IDENTITY
coluna excede o intervalo deint
e é aumentada parabigint
).Isso é simplesmente uma prática melhor, já que outras formas
AddWithValue()
podem causar problemas. Por exemplo, os tipos errados serão inferidos aqui:No
int
intervalo, é improvável que você encontre muitos problemas, mas se você estender isso para outros tipos e estiver usando consultas ad hoc em oposição a chamadas de procedimento armazenado com parâmetros fortemente tipados, as coisas podem ficar muito ruins muito rapidamente . Como David apontou, você pode obter planos ruins, por exemplo, conversões implícitas que podem fazer com que as buscas mudem para varreduras. Permitir que o padrãonvarchar
seja passado para umavarchar
coluna pode causar grandes problemas de desempenho, como Jonathan Kehayias demonstra aqui. E permitir que o .NET determine o comprimento do parâmetro com base no comprimento da string pode - dependendo da versão do SQL Server e das configurações de parametrização - levar a um plano diferente para cada comprimento único de string passado. consultas específicas mais lentas, mas podem desperdiçar muita memória, pois haverá um plano redundante armazenado e usado para cada comprimento.Essa pergunta já foi feita em outros lugares:
E Joel Coehoorn também blogou sobre os problemas de conversão de tipos, recomendando que você fique longe
AddWithValue()
(mesmo nos casos em que você "sabe" que o problema não existe):Não. Alguns tipos de dados .NET mapeiam exatamente para os tipos de dados do SQL Server, e int é um deles. E este método não está obsoleto. Veja os documentos aqui
Os problemas causados por não especificar exatamente os tipos de parâmetros são geralmente limitados a planos ruins. Se você passar um parâmetro com uma precedência de tipo de dados mais alta do que a coluna para a qual ele mapeia, os valores da coluna devem ser convertidos no tipo do parâmetro para comparação. E isso impedirá o uso do índice e exigirá uma conversão por linha.
Outro problema com a derivação do tipo de parâmetro string do valor é que o SqlClient do .NET definirá o comprimento do parâmetro para o comprimento real da string passada. Isso pode minimizar o tráfego de rede e os requisitos de memória, mas pode alterar o cache do plano de consulta e o comportamento de reutilização no SQL Server. Para invocações de procedimento armazenado, não importa, mas para lotes SQL ad-hoc, você pode acabar com um plano em cache diferente para cada comprimento de string.
Se você passar um parâmetro numérico/decimal com precisão excessiva, isso pode causar a perda de escala no resultado, de acordo com as regras aqui , mas os parâmetros normalmente não aparecem nos cálculos.
O tipo será o tipo .NET. Se houver um mapa direto, não há problema. Se não houver um mapa direto, acho que tentará uma conversão implícita.