Mi empresa utiliza una aplicación que tiene problemas de rendimiento bastante importantes. Hay una serie de problemas con la base de datos en sí, en los que estoy trabajando, pero muchos de los problemas están relacionados únicamente con la aplicación.
En mi investigación descubrí que hay millones de consultas que llegan a la base de datos de SQL Server que consultan tablas vacías. Tenemos alrededor de 300 tablas vacías y algunas de esas tablas se consultan hasta 100-200 veces por minuto. Las tablas no tienen nada que ver con nuestra área de negocios y son esencialmente partes de la aplicación original que el proveedor no eliminó cuando mi empresa las contrató para producir una solución de software para nosotros.
Además del hecho de que sospechamos que nuestro registro de errores de la aplicación se está inundando con errores relacionados con este problema, el proveedor nos asegura que no hay un impacto en el rendimiento o la estabilidad ni de la aplicación ni del servidor de la base de datos. El registro de errores se inunda en la medida en que no podemos ver más de 2 minutos de errores para hacer diagnósticos.
El costo real de estas consultas obviamente será bajo en términos de ciclos de CPU, etc. ¿Pero alguien puede sugerir cuál sería el efecto en SQL Server y la aplicación? Sospecharía que la mecánica real de enviar una solicitud, confirmarla, procesarla, devolverla y acusar recibo de la solicitud tendría un impacto en el rendimiento.
Utilizamos SQL Server 2008 R2, Oracle Weblogic 11g para la aplicación.
@ Frisbee: Para resumir, creé una tabla que contiene el texto de consulta que golpeó las tablas vacías en la base de datos de la aplicación, luego pregunté por todos los nombres de tablas que sé que están vacíos y obtuve una lista muy larga. El mayor éxito fue de 2.7 millones de ejecuciones durante 30 días de tiempo de actividad, teniendo en cuenta que la aplicación generalmente se usa de 8 am a 6 pm, por lo que esos números están más concentrados en las horas de funcionamiento. Múltiples tablas, múltiples consultas, probablemente algunas relacionadas a través de combinaciones, otras no. El primer éxito (2.7 millones en ese momento) fue una simple selección de una sola tabla vacía con una cláusula where, sin uniones. Esperaría que las consultas más grandes con uniones a las tablas vacías pudieran incluir actualizaciones a las tablas vinculadas, pero lo comprobaré y actualizaré esta pregunta lo antes posible.
Actualización: Hay 1000 consultas con un recuento de ejecución de entre 1043 y 4622614 (más de 2.5 meses). Tendré que cavar más para saber cuándo se origina el plan en caché. Esto es solo para darle una idea del alcance de las consultas. La mayoría son razonablemente complejos con más de 20 uniones.
@ srutzky- sí, creo que hay una columna de fecha relacionada con el momento en que se compiló el plan, por lo que sería interesante, así que lo comprobaré. Me pregunto si los límites de subprocesos serían un factor en absoluto cuando el SQL Server se encuentra en un clúster de VMware. Pronto será un Dell PE 730xD dedicado, afortunadamente.
@Frisbee - Perdón por la respuesta tardía. Como sugirió, ejecuté un select * de la tabla vacía 10,000 veces en 24 subprocesos usando SQLQueryStress (en realidad 240,000 iteraciones) y alcancé 10,000 Solicitudes de lote / seg inmediatamente. Luego reduje a 1000 veces más de 24 hilos y llegué a menos de 4.000 solicitudes de lote / segundo. También probé 10,000 iteraciones en solo 12 subprocesos (por lo tanto, 120000 iteraciones totales) y esto produjo un sostenido 6,505 lotes / seg. El efecto en la CPU fue realmente notable, alrededor del 5-10% del uso total de la CPU durante cada ejecución de prueba. Las esperas de la red fueron insignificantes (como 3 ms con el cliente en mi estación de trabajo), pero el impacto de la CPU fue seguro, lo que es bastante concluyente en lo que a mí respecta. Parece reducirse al uso de la CPU y un poco de archivo de base de datos innecesario IO. El total de ejecuciones / segundo funciona en poco menos de 3000, que es más que en producción, sin embargo, estoy probando solo una de las docenas de consultas como esta. El efecto neto de cientos de consultas que llegan a tablas vacías a una velocidad de entre 300 y 4000 veces por minuto, por lo tanto, no sería insignificante cuando se trata del tiempo de CPU. Todas las pruebas realizadas contra un PE 730xD inactivo con doble matriz flash y 256 GB de RAM, 12 núcleos modernos.
@ srutzky- buen pensamiento. SQLQueryStress parece utilizar la agrupación de conexiones de forma predeterminada, pero de todos modos eché un vistazo y descubrí que sí, la casilla para la agrupación de conexiones está marcada. Actualización a seguir
@ srutzky: la agrupación de conexiones aparentemente no está habilitada en la aplicación, o si lo está, no está funcionando. Hice un seguimiento del generador de perfiles y descubrí que las conexiones tienen EventSubClass "1 - No agrupado" para los eventos de inicio de sesión de auditoría.
RE: Agrupación de conexiones: verificó los weblogics y encontró la agrupación de conexiones habilitada. Corrió más rastros en vivo y encontró signos de agrupación que no ocurren correctamente / en absoluto:
Y así es como se ve cuando ejecuto una sola consulta sin combinaciones en una tabla poblada; las excepciones dicen "Se produjo un error relacionado con la red o específico de la instancia al establecer una conexión con SQL Server. No se encontró el servidor o no fue accesible. Verifique que el nombre de la instancia sea correcto y que SQL Server esté configurado para permitir conexiones remotas. (proveedor: proveedor de canalizaciones con nombre, error: 40 - No se pudo abrir una conexión a SQL Server) "Tenga en cuenta el contador de solicitudes por lotes. Hacer ping al servidor durante el tiempo en que se generan las excepciones da como resultado una respuesta de ping exitosa.
Actualización: dos ejecuciones de prueba consecutivas, la misma carga de trabajo (seleccione * fromEmptyTable), agrupación habilitada / no habilitada. Un poco más de uso de CPU y muchas fallas y nunca supera las 500 solicitudes por lote / seg. Las pruebas muestran 10,000 lotes / segundo y no hay fallas con la agrupación activada, y alrededor de 400 lotes / segundo y luego muchas fallas debido a la desactivación de la agrupación. Me pregunto si estas fallas están relacionadas con la falta de disponibilidad de conexión.
@ srutzky- Seleccione Count (*) de sys.dm_exec_connections;
Agrupación habilitada: 37 consistentemente, incluso después de que se detiene la prueba de carga
Agrupación deshabilitada: 11-37 dependiendo de si se
producen o no excepciones en SQLQueryStress, es decir: cuando esos canales aparecen en el
gráfico Batches / sec, las excepciones ocurren en SQLQueryStress, y el
número de conexiones cae a 11, luego vuelve gradualmente a 37 cuando los lotes comienzan a alcanzar su punto máximo y no se producen las excepciones. Muy, muy interesante
Las conexiones máximas en ambas instancias de prueba / en vivo se establecen en el valor predeterminado de 0.
He verificado los registros de la aplicación y no puedo encontrar problemas de conectividad, sin embargo, solo hay un par de minutos de registro disponibles debido a la gran cantidad y el tamaño de los errores, es decir: muchos errores de seguimiento de la pila. Un colega en soporte de aplicaciones informa que se produce un número considerable de errores HTTP relacionados con la conectividad. Parecería basado en esto, que por alguna razón la aplicación no está agrupando conexiones correctamente y como resultado, el servidor se está quedando sin conexiones repetidamente. Buscaré más en los registros de aplicaciones. Me pregunto ¿hay alguna manera de demostrar que esto está sucediendo en la producción desde el lado del servidor SQL?
@ srutzky- Gracias. Revisaré la configuración de weblogic mañana y la actualizaré. Sin embargo, estaba pensando en las meras 37 conexiones: si SQLQueryStress está haciendo 12 subprocesos a 10,000 iteraciones = 120,000 declaraciones de selección no agrupadas, ¿no debería eso significar que cada selección crea una conexión distinta a la instancia de SQL?
@ srutzky: los Weblogics están configurados para agrupar conexiones, por lo que debería funcionar bien. La agrupación de conexiones se configura de esta manera, en cada uno de los 4 weblogics de carga equilibrada:
- Capacidad inicial: 10
- Capacidad Máxima: 50
- Capacidad mínima: 5
Cuando aumento el número de subprocesos que ejecutan la selección de la consulta de tabla vacía, el número de conexiones alcanza un pico de alrededor de 47. Con la agrupación de conexiones deshabilitada, veo consistentemente un menor número de solicitudes de lote / segundo (de 10,000 a aproximadamente 400). Lo que sucederá cada vez es que las 'excepciones' en SQLQueryStress ocurren poco después de que los lotes / seg entren en un canal. Está relacionado con la conectividad, pero no puedo entender exactamente por qué sucede esto. Cuando no se están ejecutando pruebas, # connections baja a aproximadamente 12.
Con la agrupación de conexiones deshabilitada, tengo problemas para entender por qué ocurren las excepciones, pero ¿tal vez es una pregunta / pregunta de stackExchange completamente diferente para Adam Machanic?
@srutzky Me pregunto, entonces, ¿por qué ocurren las excepciones sin la agrupación habilitada, a pesar de que SQL Server no se está quedando sin conexiones?
SELECT COUNT(*) FROM sys.dm_exec_connections;
para ver si el valor es muy diferente entre tener la agrupación habilitada o no. Basado en esos errores, creo que habría muchas más conexiones cuando la agrupación esté deshabilitada.Pooling=false
oMax Pool Size
?Respuestas:
Sí, e incluso hay algunos factores adicionales, pero el grado en que cualquiera de estos realmente está afectando su sistema es imposible de decir sin analizar el sistema.
Dicho esto, está preguntando qué podría ser un problema, y hay algunas cosas que mencionar, incluso si algunas de ellas no son actualmente un factor en su situación particular. Tu dices eso:
Incluso podría haber más, pero esto debería ayudar a tener una idea de las cosas. Y tenga en cuenta que, como la mayoría de los problemas de rendimiento, todo es cuestión de escala. Todos los elementos mencionados anteriormente no son problemas si se golpean una vez por minuto. Es como probar un cambio en su estación de trabajo o en la base de datos de desarrollo: siempre funciona con solo 10 a 100 filas en las tablas. Mueva ese código a producción y demore 10 minutos en ejecutarse, y alguien seguramente dirá: "bueno, funciona en mi caja" ;-). Es decir, solo debido al gran volumen de llamadas que se están haciendo, está viendo un problema, pero esa es la situación que existe.
Entonces, incluso con 1 millón de consultas inútiles de 0 filas, eso equivale a:
Se mantienen más conexiones que ocupan más memoria. ¿Cuánta RAM física no utilizada tienes? esa memoria se utilizaría mejor para ejecutar consultas y / o caché del plan de consultas. El peor de los casos sería que se haya quedado sin memoria física y que SQL Server tenga que comenzar a usar memoria virtual (intercambio), ya que eso ralentiza las cosas (verifique el registro de errores de SQL Server para ver si recibe mensajes sobre la memoria paginada).
Y por si alguien menciona, "bueno, hay una agrupación de conexiones". Sí, eso definitivamente ayuda a reducir la cantidad de conexiones necesarias. Pero con consultas llegando hasta 200 veces por minuto, esa es una gran cantidad de actividad concurrente y aún deben existir conexiones para las solicitudes legítimas. Haga una
SELECT * FROM sys.dm_exec_connections;
para ver cuántas conexiones activas está manteniendo.Si no estoy equivocado sobre lo que he estado diciendo aquí, entonces me parece que, incluso a pequeña escala, este es un tipo de ataque DDoS en su sistema ya que está inundando la red y su SQL Server con solicitudes falsas , evitando que las solicitudes reales lleguen a SQL Server o sean procesadas por SQL Server.
fuente
Si las mesas están siendo golpeadas 100-200 veces por minuto, entonces están (con suerte) en la memoria. La carga en el servidor es muy muy baja. A menos que tenga una CPU o memoria alta en el servidor de la base de datos, esto probablemente no sea un problema.
Sí, las consultas toman bloqueos compartidos, pero es de esperar que no bloqueen ningún bloqueo de actualización ni bloqueen ningún bloqueo de actualización. ¿Tiene alguna actualización, inserción o eliminación en estas tablas? Si no, simplemente lo dejaría pasar; si tiene problemas de rendimiento, debe haber peces más grandes para freír desde la perspectiva del servidor de bases de datos.
Ejecuté una prueba con 100.000 recuentos seleccionados (*) en una tabla vacía y se ejecutó en 32 segundos y las consultas se realizaron a través de una red. Entonces 1/3 milisegundos. A menos que su red se sobrecargue, esto ni siquiera afecta al cliente. Si tiene problemas de rendimiento importantes, estas consultas en blanco de 1/3 milisegundos no son lo que está matando la aplicación.
Y estos podrían ser solo parte de una unión izquierda que toma algunos datos de tipo estático que no forman parte de la aplicación actual. Se podría encadenar con otras consultas, por lo que no es un viaje de ida y vuelta adicional. Si es así, es descuidado pero ni siquiera está causando más tráfico.
Así que volvamos a mirar las declaraciones reales. ¿Ves actualizaciones, adiciones o eliminaciones en estas tablas?
Sí, muchas tablas vacías y consultas a tablas vacías indican una codificación descuidada. Pero si tiene problemas importantes de rendimiento, esta no es la causa, a menos que tenga algunas operaciones de escritura realmente descuidadas que también están sucediendo con estas tablas.
fuente
En general, en cada consulta se realizan los siguientes pasos:
muchas consultas, como mencionó, pueden causar una carga adicional en un sistema que ya es pesado: carga adicional en las conexiones, CPU, RAM y E / S.
fuente