sql >> Base de Datos >  >> RDS >> Sqlserver

¿Cuándo es mejor escribir sql ad hoc vs procedimientos almacenados?

SQL Server almacena en caché los planes de ejecución para consultas ad-hoc, por lo que (descontando el tiempo que toma la primera llamada) los dos enfoques serán idénticos en términos de velocidad.

En general, el uso de procedimientos almacenados significa tomar una parte del código que necesita su aplicación (las consultas T-SQL) y colocarlo en un lugar que no está bajo control de fuente (que puede ser, pero por lo general no es ) y donde puede ser alterado por otros sin su conocimiento.

Tener las consultas en un lugar central como este puede ser algo bueno, dependiendo de cuántas aplicaciones diferentes necesiten acceder a los datos que representan. Por lo general, me resulta mucho más fácil mantener las consultas utilizadas por una aplicación residente en el propio código de la aplicación.

A mediados de la década de 1990, la sabiduría convencional decía que los procedimientos almacenados en SQL Server eran el camino a seguir en situaciones de rendimiento crítico, y en ese momento definitivamente lo eran. Sin embargo, las razones detrás de este CW no han sido válidas durante mucho tiempo.

Actualización: Además, con frecuencia en los debates sobre la viabilidad de los procedimientos almacenados, se invoca la necesidad de evitar la inyección SQL en defensa de los procesos. Seguramente, nadie en su sano juicio piensa que ensamblar consultas ad hoc a través de la concatenación de cadenas es lo correcto (aunque esto solo lo expondrá a un ataque de inyección SQL si está concatenando entrada de usuario ). Obviamente, las consultas ad hoc deben parametrizarse, no solo para evitar el monstruo oculto de un ataque de inyección sql, sino también para hacer su vida como programador más fácil en general (a menos que disfrute tener que averiguar cuándo usar single comillas alrededor de sus valores).

Actualización 2: He investigado más. Basado en este documento técnico de MSDN , parece que la respuesta depende exactamente de lo que quiera decir con "ad-hoc" con sus consultas. Por ejemplo, una consulta simple como esta:

SELECT ID, DESC FROM tblSTUFF WHERE ITEM_COUNT > 5

... lo hará tener su plan de ejecución en caché. Además, debido a que la consulta no contiene ciertos elementos descalificadores (como casi cualquier cosa que no sea un simple SELECCIONAR de una tabla), SQL Server en realidad "parametrizará automáticamente" la consulta y reemplazará la constante literal "5" con un parámetro, y almacenará en caché. el plan de ejecución para la versión parametrizada. Esto significa que si luego ejecuta this consulta ad-hoc:

SELECT ID, DESC FROM tblSTUFF WHERE ITEM_COUNT > 23

... podrá usar el plan de ejecución en caché.

Desafortunadamente, la lista de elementos de consulta que descalifican para la parametrización automática es larga (por ejemplo, olvídese de usar DISTINCT , TOP , UNION , GROUP BY , OR etc.), por lo que realmente no puede contar con esto para el rendimiento.

Si tiene una consulta "supercompleja" que no se parametrizará automáticamente, como:

SELECT ID, DESC FROM tblSTUFF WHERE ITEM_COUNT > 5 OR ITEM_COUNT < 23

... seguirá siendo almacenado en caché por el texto exacto de la consulta, por lo que si su aplicación llama a esta consulta con los mismos valores literales "codificados" repetidamente, cada consulta después de la primera reutilizará el plan de ejecución almacenado en caché (y ser tan rápido como un proceso almacenado).

Si los valores literales cambian (según las acciones del usuario, por ejemplo, como filtrar u ordenar los datos vistos), las consultas no se beneficiarán del almacenamiento en caché (excepto ocasionalmente cuando accidentalmente coincidan exactamente con una consulta reciente).

La forma de beneficiarse del almacenamiento en caché con consultas "ad-hoc" es parametrizarlas. Crear una consulta sobre la marcha en C# como esta:

int itemCount = 5;
string query = "DELETE FROM tblSTUFF WHERE ITEM_COUNT > " + 
        itemCount.ToString();

Es incorrecto. La forma correcta (usando ADO.Net) sería algo como esto:

using (SqlConnection conn = new SqlConnection(connStr))
{
    SqlCommand com = new SqlCommand(conn);
    com.CommandType = CommandType.Text;
    com.CommandText = 
        "DELETE FROM tblSTUFF WHERE ITEM_COUNT > @ITEM_COUNT";
    int itemCount = 5;
    com.Parameters.AddWithValue("@ITEM_COUNT", itemCount);
    com.Prepare();
    com.ExecuteNonQuery();
}

La consulta no contiene literales y ya está completamente parametrizada, por lo que las consultas posteriores que utilicen la instrucción parametrizada idéntica utilizarían el plan almacenado en caché (incluso si se llama con valores de parámetro diferentes). Tenga en cuenta que el código aquí es prácticamente el mismo que el código que usaría para llamar a un procedimiento almacenado de todos modos (la única diferencia es CommandType y CommandText), por lo que de alguna manera se reduce a dónde desea que el texto de esa consulta "viva". " (en su código de aplicación o en un procedimiento almacenado).

Finalmente, si por consultas "ad-hoc" quiere decir que está construyendo dinámicamente consultas con diferentes columnas, tablas, parámetros de filtrado y demás, como quizás estos:

SELECT ID, DESC FROM tblSTUFF WHERE ITEM_COUNT > 5

SELECT ID, FIRSTNAME, LASTNAME FROM tblPEEPS 
    WHERE AGE >= 18 AND LASTNAME LIKE '%What the`

SELECT ID, FIRSTNAME, LASTNAME FROM tblPEEPS 
    WHERE AGE >= 18 AND LASTNAME LIKE '%What the`
    ORDER BY LASTNAME DESC

... entonces prácticamente no puedes haz esto con procedimientos almacenados (sin el EXEC hack del que no se habla en la sociedad educada), por lo que el punto es discutible.

Actualización 3: Aquí está el único realmente bueno relacionado con el rendimiento razón (en la que puedo pensar, de todos modos) para usar un procedimiento almacenado. Si su consulta es de larga duración, donde el proceso de compilación del plan de ejecución lleva mucho más tiempo que la ejecución real, y la consulta solo se llama con poca frecuencia (como un informe mensual, por ejemplo), entonces ponerlo en un procedimiento almacenado podría hacer que SQL Server mantenga el plan compilado en la memoria caché el tiempo suficiente para que aún esté disponible el próximo mes. Sin embargo, me sorprende si eso es cierto o no.