c# - studio - evolucion de ado net
Ejecutar mĂșltiples comandos SQL en un viaje de ida y vuelta (6)
Estoy creando una aplicación y quiero agrupar varias consultas en un solo viaje de ida y vuelta a la base de datos. Por ejemplo, digamos que una sola página necesita mostrar una lista de usuarios, una lista de grupos y una lista de permisos.
Así que he almacenado procs (o simplemente comandos de SQL simples como "seleccionar * de Usuarios"), y quiero ejecutar tres de ellos. Sin embargo, para poblar esta página tengo que hacer 3 viajes de ida y vuelta.
Ahora podría escribir un solo proceso almacenado ("getUsersTeamsAndPermissions") o ejecutar un solo comando SQL "select * from Users; exec getTeams; select * from Permissions".
Pero me preguntaba si había una mejor manera de especificar hacer 3 operaciones en un solo viaje redondo. Los beneficios incluyen ser más fácil de realizar una prueba unitaria y permitir que el motor de la base de datos paralice las consultas.
Estoy usando C # 3.5 y SQL Server 2008.
¿Construir una tabla temporal? Inserte todos los resultados en la tabla temporal y luego select * from @temp-table
como en,
@temptable=....
select @temptable.field=mytable.field from mytable
select @temptable.field2=mytable2.field2 from mytable2
etc ... Solo un viaje a la base de datos, aunque no estoy seguro de que sea realmente más eficiente.
Algo como this . Es probable que el ejemplo no sea muy bueno, ya que no dispone de los objetos correctamente, pero se entiende la idea. Aquí hay una versión limpia:
using (var connection = new SqlConnection(ConnectionString))
using (var command = connection.CreateCommand())
{
connection.Open();
command.CommandText = "select id from test1; select id from test2";
using (var reader = command.ExecuteReader())
{
do
{
while (reader.Read())
{
Console.WriteLine(reader.GetInt32(0));
}
Console.WriteLine("--next command--");
} while (reader.NextResult());
}
}
El comando de varias partes y las opciones de procedimiento almacenado que menciona son las dos opciones. No puede hacerlos de tal manera que estén "paralelizados" en la db. Sin embargo, ambas opciones dan como resultado un solo viaje de ida y vuelta , así que estás bien allí. No hay manera de enviarlos más eficientemente. A partir del servidor SQL 2005, un comando multiparte que está completamente parametrizado es muy eficiente.
Editar : agregar información sobre por qué meterse en una sola llamada.
Si bien no desea preocuparse demasiado por la reducción de llamadas, puede haber razones legítimas para esto.
- Una vez me limité a un controlador ODBC de mala calidad contra un mainframe, ¡y hubo una sobrecarga de 1.2 segundos en cada llamada! Lo digo en serio. Hubo momentos en que metí un poco más en mis llamadas de db. No es bonito.
- También puede encontrarse en una situación en la que tenga que configurar sus consultas de SQL en algún lugar, y no puede hacer solo 3 llamadas: tiene que ser una. No debería ser así, mal diseño, pero lo es. ¡Haz lo que tengas que hacer!
- A veces, por supuesto, puede ser muy bueno encapsular varios pasos en un procedimiento almacenado. Sin embargo, por lo general no para guardar viajes de ida y vuelta, sino para transacciones más estrictas, obtener ID para nuevos registros, restringir los permisos, proporcionar encapsulación, bla, bla, bla. ( Pero, por favor, no comience a usar procedimientos almacenados todo el tiempo ) .
En primer lugar, 3 viajes de ida y vuelta no es realmente un gran problema. Si estuvieras hablando de 300 viajes de ida y vuelta, eso sería otro asunto, pero para solo 3 viajes de ida y vuelta me gustaría que este sea un caso de optimización prematura.
Dicho esto, la forma en que lo haría probablemente sería ejecutar los 3 procesos almacenados utilizando SQL:
exec dbo.p_myproc_1 @param_1 = @in_param_1, @param_2 = @in_param_2
exec dbo.p_myproc_2
exec dbo.p_myproc_3
Luego puede recorrer los conjuntos de resultados devueltos como lo haría si ejecutara directamente varios conjuntos de filas.
Hacer un viaje de ida y vuelta frente a tres será más eficiente. La pregunta es si vale la pena. Todo el conjunto de herramientas y el marco de ADO.Net y C # 3.5 se opone a lo que intenta hacer. TableAdapters, Linq2SQL, EF, todo esto para tratar con una simple llamada semántica == one-resultset. Por lo tanto, puede perder algo de productividad seria al tratar de batir el Marco para su presentación.
Yo diría que a menos que tenga algunas mediciones serias que muestren que necesita reducir el número de viajes de ida y vuelta, absténgase. Si terminas requiriendo esto, entonces usa un procedimiento almacenado para al menos dar un tipo de semántica de API.
Pero si su consulta es realmente lo que publicó (es decir, seleccione todos los usuarios, todos los equipos y todos los permisos), entonces obviamente tendrá mucho más por delante antes de reducir los viajes de ida y vuelta ... primero reduzca los resultados.
Yo este enlace podría ser útil.
Considere usar al menos la misma conexión abierta; de acuerdo con lo que dice here , abrir una conexión es casi el líder principal en costos de rendimiento en Entity-Framework.