Sé que los procedimientos almacenados son más eficientes a través de la ruta de ejecución (que el sql en línea en las aplicaciones). Sin embargo, cuando se presiona, no sé muy bien por qué.
Me gustaría saber el razonamiento técnico para esto (de manera que pueda explicárselo a alguien más adelante).
¿Alguien puede ayudarme a formular una buena respuesta?
Respuestas:
Creo que este sentimiento era cierto en un momento, pero no en las versiones actuales de SQL Server. Todo el problema era que en los viejos tiempos las sentencias SQL ad hoc no podían optimizarse correctamente porque SQL Server solo podía optimizar / compilar a nivel de lote. Ahora tenemos una optimización a nivel de enunciado, por lo que una consulta correctamente parametrizada proveniente de una aplicación puede aprovechar el mismo plan de ejecución que esa consulta incrustada en un procedimiento almacenado.
Todavía prefiero los procedimientos almacenados del lado de DBA por los siguientes motivos (y varios de ellos pueden tener un gran impacto en el rendimiento):
sys.sql_modules
, para referencias a objetos específicos) hace la vida de todos mucho más fácil.SET ANSI_WARNINGS ON
y la otra podría tenerSET ANSI_WARNINGS OFF
, y cada una tendría su propia copia del plan. El plan que obtienen depende de los parámetros en uso, las estadísticas establecidas, etc. la primera vez que se llama a la consulta en cada caso, lo que podría conducir a planes diferentes y, por lo tanto, a un rendimiento muy diferente.Dicho todo esto, es probable que esta pregunta suscite más argumentos religiosos que el debate técnico. Si vemos que eso sucede, probablemente lo cerremos.
fuente
Si bien respeto al remitente, discrepo humildemente con la respuesta proporcionada y no por "razones religiosas". En otras palabras, creo que no hay ninguna instalación que haya proporcionado Microsoft que disminuya la necesidad de orientación para usar los procedimientos almacenados.
Cualquier orientación proporcionada a un desarrollador que favorezca el uso de consultas SQL de texto sin procesar debe estar llena de muchas advertencias, de modo que creo que el consejo más prudente es alentar en gran medida el uso de procedimientos almacenados y desalentar a sus equipos de desarrolladores a participar en la práctica de incrustar sentencias de SQL en el código, o enviar solicitudes de SQL basadas en texto sin formato y sin formato, fuera de los SPROC de SQL (procedimientos almacenados).
Creo que la respuesta simple a la pregunta de por qué usar un SPROC es como supuso el remitente: los SPROC se analizan, optimizan y compilan. Como tal, sus planes de consulta / ejecución se almacenan en caché porque ha guardado una representación estática de una consulta y, normalmente, la variará solo por parámetros, lo que no es cierto en el caso de las instrucciones SQL copiadas / pegadas que probablemente se transformarán de página a página y componente / nivel, y a menudo se varían en la medida en que se pueden especificar diferentes tablas, incluso nombres de bases de datos, de llamada a llamada. Permitiendo este tipo de dinámica ad hocEl envío de SQL disminuye en gran medida la probabilidad de que DB Engine reutilice el plan de consulta para sus declaraciones ad hoc, de acuerdo con algunas reglas muy estrictas. Aquí, hago la distinción entre consultas dinámicas ad hoc (en el espíritu de la pregunta planteada) versus el uso del eficiente Sistema SPROC sp_executesql.
Más específicamente, hay los siguientes componentes:
Cuando se emite una declaración SQL desde una página web, denominada "declaración ad hoc", el motor busca un plan de ejecución existente para manejar la solicitud. Debido a que este es un texto enviado por un usuario, será ingerido, analizado, compilado y ejecutado, si es válido. En este momento recibirá un costo de consulta de cero. El costo de la consulta se usa cuando el motor de base de datos usa su algoritmo para determinar qué planes de ejecución desalojar de la memoria caché.
Las consultas ad hoc reciben un valor de costo de consulta original de cero, por defecto. Tras la posterior ejecución del mismo texto de consulta ad hoc, por otro proceso de usuario (o el mismo), el costo de la consulta actual se restablece al costo de compilación original. Dado que nuestro costo de compilación de consultas ad hoc es cero, esto no es un buen augurio para la posibilidad de reutilización. Obviamente, cero es el número entero menos valorado, pero ¿por qué sería desalojado?
Cuando surgen presiones de memoria, y lo harán si tiene un sitio de uso frecuente, el motor de base de datos utiliza un algoritmo de limpieza para determinar cómo puede recuperar la memoria que está utilizando la caché de procedimientos. Utiliza el costo de la consulta actual para decidir qué planes desalojar. Como puede suponer, los planes con un costo de cero son los primeros en ser desalojados de la memoria caché porque cero significa esencialmente "no hay usuarios actuales o referencias a este plan".
Por lo tanto, es bastante probable que dicho plan sea desalojado primero cuando surjan presiones de memoria.
Por lo tanto, si tiene un servidor incorporado con mucha memoria "más allá de sus necesidades", es posible que no experimente este problema con tanta frecuencia como un servidor ocupado que solo tiene memoria "suficiente" para manejar su carga de trabajo. (Lo sentimos, la capacidad de memoria del servidor y la utilización son algo subjetivas / relativas, aunque el algoritmo no lo es).
Ahora, si estoy objetivamente incorrecto sobre uno o más puntos, ciertamente estoy abierto a ser corregido.
Por último, el autor escribió:
"Ahora tenemos una optimización a nivel de declaración, por lo que una consulta correctamente parametrizada proveniente de una aplicación puede aprovechar el mismo plan de ejecución que esa consulta incorporada en un procedimiento almacenado".
Creo que el autor se refiere a la opción "optimizar para cargas de trabajo ad hoc".
Si es así, esta opción permite un proceso de dos pasos que evita enviar inmediatamente el plan de consulta completo a la caché de procedimientos. Solo envía un trozo de consulta más pequeño allí. Si se envía una llamada de consulta exacta al servidor mientras el código auxiliar de consulta todavía está en la caché de procedimientos, el plan completo de ejecución de la consulta se guarda en la caché de procedimientos, en ese momento. Esto ahorra memoria, que durante los incidentes de presión de memoria, puede permitir que el algoritmo de desalojo expulse su código auxiliar con menos frecuencia que un plan de consulta más grande que se almacenó en caché. Nuevamente, esto depende de la memoria y la utilización de su servidor.
Sin embargo, debe activar esta opción, ya que está desactivada de forma predeterminada.
Por último, quiero enfatizar que, a menudo, la razón por la cual los desarrolladores incrustarían SQL en páginas, componentes y otros lugares, es porque desean ser flexibles y enviar consultas SQL dinámicas al motor de la base de datos. Por lo tanto, en un caso de uso del mundo real, es poco probable que se envíe el mismo texto, llamada sobre llamada, al igual que el almacenamiento en caché / eficiencia que buscamos, al enviar consultas ad hoc a SQL Server.
Para obtener información adicional, consulte:
https://technet.microsoft.com/en-us/library/ms181055(v=sql.105).aspx
http://sqlmag.com/database-performance-tuning/don-t-fear-dynamic-sql
Mejor
Henry
fuente
TLDR: no hay una diferencia de rendimiento apreciable entre los dos, siempre que su sql en línea esté parametrizado.
Estas son las razones por las que he eliminado gradualmente los procedimientos almacenados:
Ejecutamos un entorno de aplicación 'beta', un entorno paralelo a la producción que comparte la base de datos de producción. Debido a que el código db está en el nivel de la aplicación y que los cambios en la estructura db son raros, podemos permitir que las personas confirmen nuevas funciones más allá del control de calidad y realicen implementaciones fuera de la ventana de implementación de producción, pero aún así proporcionan funcionalidad de producción y soluciones no críticas. Esto no sería posible si la mitad del código de la aplicación estuviera en la base de datos.
Practicamos devops a nivel de base de datos (octopus + dacpacs). Sin embargo, si bien la capa empresarial y las versiones superiores se pueden purgar y reemplazar básicamente, y la recuperación es todo lo contrario, eso no es cierto para los cambios incrementales y potencialmente destructivos que deben ir a las bases de datos. En consecuencia, preferimos mantener nuestras implementaciones de DB más ligeras y menos frecuentes.
Para evitar copias casi exactas del mismo código para parámetros opcionales, a menudo usaremos un patrón 'donde @var es nulo o @ var = table.field'. Con un proceso almacenado, es probable que obtenga el mismo plan de ejecución, a pesar de las intenciones bastante diferentes, y por lo tanto experimente problemas de rendimiento o elimine los planes en caché con sugerencias de 'recompilación'. Sin embargo, con un simple código que agrega un comentario de "firma" al final del sql, podemos forzar diferentes planes basados en qué variables eran nulas (no se debe interpretar como un plan diferente para todas las combinaciones de variables, solo nulo vs no nulo).
Puedo hacer cambios dramáticos en los resultados con solo cambios menores sobre la marcha al sql. Por ejemplo, puedo tener una declaración que se cierra con dos CTE, "Raw" y "ReportReady". No hay nada que diga que se deben usar ambos CTE. Mi declaración sql puede ser:
...
seleccione * de {(formato)} "
Esto me permite utilizar exactamente el mismo método de lógica de negocios para una llamada API simplificada y un informe que debe ser más detallado para garantizar que no duplique la lógica complicada.
Hay razones válidas para usar procs:
Seguridad: aquí tienes otra capa por la que debe pasar la aplicación. Si la cuenta del servicio de la aplicación no puede tocar tablas, pero solo tiene permiso de "ejecución" en los procs, tiene alguna protección adicional. Esto no lo hace un hecho dado que tiene un costo, pero es una posibilidad.
Reutilización: si bien diría que la reutilización debería suceder en gran medida en la capa empresarial para asegurarse de que no se pasen por alto las reglas comerciales no relacionadas con la base de datos, todavía tenemos el tipo de software y funciones de utilidad de bajo nivel "utilizado en todas partes".
Hay algunos argumentos que realmente no son compatibles con los procs o que se mitigan fácilmente de la OMI:
Reutilización: mencioné esto anteriormente como un "plus", pero también quería mencionarlo aquí que la reutilización debería ocurrir en gran medida en la capa empresarial. Un proceso para insertar un registro no debe considerarse "reutilizable" cuando la capa empresarial también puede estar verificando otros servicios que no son de base de datos.
Hinchazón del plan de caché: la única forma en que esto será un problema es si está concatenando valores en lugar de parametrizando. El hecho de que rara vez obtienes más de un plan por proceso en realidad a menudo te perjudica cuando tienes un 'o' en una consulta
Tamaño de la declaración: un kb adicional de declaraciones sql sobre el nombre del proceso generalmente será insignificante en relación con los datos que regresan. Si está bien para las entidades, está bien para mí.
Ver la consulta exacta: hacer que las consultas sean fáciles de encontrar en el código es tan simple como agregar la ubicación de la llamada como un comentario al código. Hacer que el código se pueda copiar de código C # a ssms es tan fácil como una interpolación creativa y el uso de comentarios:
Inyección SQL: parametrice sus consultas. Hecho. En realidad, esto se puede deshacer si el proceso está usando sql dinámico.
Omitir la implementación: también practicamos devops a nivel de base de datos, por lo que esta no es una opción para nosotros.
"Lento en la aplicación, rápido en SSMS": este es un problema de almacenamiento en caché del plan que afecta a ambos lados. Las opciones establecidas simplemente provocan la compilación de un nuevo plan que parece solucionar el problema de las variables THE ONE SET OFF. Esto solo responde por qué ve resultados diferentes: las opciones establecidas NO solucionan el problema del rastreo de parámetros.
Los planes de ejecución de SQL en línea no se almacenan en caché: simplemente son falsos. Una declaración parametrizada, al igual que el nombre del proceso, se codifica rápidamente y luego ese hash busca un plan. Es 100% igual.
Para ser claros, estoy hablando de código sql en línea no generado sin procesar de un ORM: solo usamos Dapper, que es un micro ORM en el mejor de los casos.
https://weblogs.asp.net/fbouma/38178
/programming//a/15277/852208
fuente