Aplicación que consulta tablas vacías


10

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. Este es el resultado de SQLSentry

@ 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: ingrese la descripción de la imagen aquí

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.

ingrese la descripción de la imagen aquí

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.

ingrese la descripción de la imagen aquí

@ 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?


1
Peter, con las actualizaciones más recientes en mente con respecto a la agrupación de conexiones, parece que ahora necesita volver a ejecutar sus pruebas con SQLQueryStress pero con la agrupación de conexiones desactivada . Eso sería un reflejo más preciso de los efectos de cómo funciona la aplicación, y creo que mostrará un aumento en el uso de la CPU e incluso el uso de RAM.
Solomon Rutzky

1
Peter, ¿tienes un número máximo de conexiones establecidas para el servidor? Supongo que sin la agrupación, se encuentra con un problema de demasiadas conexiones. Me pregunto si su aplicación alguna vez recibe ese error. Además, si es posible volver a ejecutar esa última prueba una vez más (con y sin agrupación habilitada), mientras se ejecuta la prueba para cada una de esas dos configuraciones, ejecute a 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.
Solomon Rutzky

1
Peter, 37 conexiones parece un máximo terriblemente bajo. Dado que el límite de conexión se establece en 0 (es decir, ilimitado), ¿está vinculada la memoria del sistema? Además, la agrupación de conexiones debe estar activada de manera predeterminada, pero está controlada por el cliente. ¿Es la aplicación una aplicación .NET? No es necesario que sea para usar la agrupación de conexiones, pero sería útil saber para encontrar la causa de esto. ¿Y puede ver qué cadena de conexión se está utilizando? ¿Especifica Pooling=falseo Max Pool Size?
Solomon Rutzky

1
Peter, cada uno de los 12 hilos está creando su propia conexión por consulta, secuencialmente para las iteraciones de 10k. Entonces, sin agrupar, la conexión puede destruirse tan pronto como el código la cierre. La agrupación mantendrá la conexión para su reutilización. Por lo tanto, tiene sentido que el número de conexiones fuera consistente al usar la agrupación. No estoy seguro de por qué 37 sin más información. ¿Cuántas conexiones hay cuando no se ejecuta ninguna prueba? Retroceder ese número dará una mejor indicación de cuántos son creados por la prueba.
Solomon Rutzky

1
La agrupación de conexiones se mantiene por cliente, no por servidor. Por lo tanto, WebLogics y SQLQueryStress deberían tener sus propios grupos de conexión (en términos de los tamaños min_pool y max_pool, etc.). Con respecto a "Con la agrupación de conexiones deshabilitada, veo un menor número de solicitudes por lote máximo / segundo": eso tiene sentido ya que toma más tiempo para cada conexión desde la aplicación para autenticar e inicializar la sesión, etc. Esto es exactamente por qué existe la agrupación de conexiones: )
Solomon Rutzky

Respuestas:


7

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.

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:

Tenemos alrededor de 300 tablas vacías y algunas de esas tablas se consultan hasta 100-200 veces por minuto.

  • Las tablas vacías que no se consultan no son un problema. Pero supongo que también podría significar que todos están siendo consultados, solo que algunos están siendo golpeados mucho más que otros.
  • El análisis de consultas y la generación del plan de ejecución no deberían ser un gran problema si el texto de la consulta que se envía sigue siendo el mismo en todas las llamadas. SQL Server analizará el texto de la consulta y lo buscará en la caché del plan. Si se encuentra, no volverá a realizar los pasos de análisis o compilación (hasta que el plan se elimine de la memoria caché).
  • Cualquier tabla, vacía o no vacía, requerirá al menos un bloqueo "compartido" para indicar que el recurso se está utilizando. Esto evita que las operaciones que requieren bloqueos exclusivos (agregar / cambiar / eliminar columnas, etc.) realicen el cambio mientras el recurso está en uso. El bloqueo y desbloqueo, incluso si se logra en menos de 1 milisegundo ya que no hay datos, aún requiere recursos del sistema (memoria y CPU) para administrar esas operaciones de bloqueo.
  • Incluso sin que los conjuntos de resultados vuelvan a la aplicación desde SQL Server, todavía hay la misma cantidad de tráfico de red que va a SQL Server, ya sea que la consulta arroje resultados o no. Se debe enviar el texto de la consulta o el nombre del procedimiento almacenado. E incluso si no se devuelven resultados, SQL Server todavía tiene que enviar algunos paquetes de red que contienen la estructura del conjunto de resultados, además de paquetes que le dicen al cliente que se está iniciando un conjunto de resultados (incluso si no se encuentran filas) y luego que el conjunto de resultados es terminando y debe estar cerrado. Y podría haber mensajes adicionales de declaraciones impresas y / o recuentos de filas.
  • Conectarse a SQL Server requiere cierta cantidad de recursos del sistema. Se necesita CPU y memoria para manejar la autenticación (así como los paquetes de red de un lado a otro) y esto también lleva tiempo. Por eso existe la agrupación de conexiones: para reducir este gasto.
  • Incluso con la agrupación de conexiones que reduce el uso de recursos del sistema, SQL Server aún necesita mantener esas conexiones y eso requiere memoria y algo de CPU mínima.
  • Incluso sin filas y, por lo tanto, un tiempo de ejecución muy rápido, la consulta aún se ejecutó. Incluso si había 10 o 10,000 filas y se extrajeron del Grupo de búferes (es decir, la memoria) ya que se usaron con frecuencia, un hilo aún necesita hacer ese trabajo. Y un hilo que está trabajando en esta consulta inútil no está funcionando en una consulta útil real.

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:

  • un extra de 2 millones de operaciones de bloqueo (cada bloqueo debe ser desbloqueado, ¿verdad?). esto es principalmente un costo de tiempo dedicado a una operación inútil en lugar de una operación útil.
  • más tráfico de red que podría estar acercándote a la saturación (no estoy seguro de qué tan probable es esto, pero aún así)
  • 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.

  • independientemente de cualquier otra cosa, esto es al menos 1 millón de veces durante cada día que un hilo que podría haber estado haciendo algo útil no estaba disponible.

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.


1

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.


¿Cuántos otros usuarios estaban en el SQL Server ejecutando consultas cuando hizo su prueba de 100k consultas? No estoy diciendo que tengo razón y que estás equivocado, pero si fueras el único en el sistema, o uno de los pocos, entonces, naturalmente, no verías un gran impacto. El problema del bloqueo no era una cuestión de bloqueo, era simplemente una cuestión de los recursos que requiere de SQL Server para bloquear y desbloquear esas páginas de datos, incluso si siempre están en el Buffer Pool. Todavía se está haciendo trabajo. Y los planificadores no son ilimitados.
Solomon Rutzky

Y no digo que estés equivocado. Otros usuarios o no, todavía es una medida válida de cuánto tiempo tomó y una medida de recursos. La carga indicada es de 100-200 por minuto. 100,000 de un cliente en 30 segundos excede esa carga en un factor de 200 a 400. Si no hay bloqueos de actualización, entonces si vino de un cliente o 100 no hace ninguna diferencia. Su respuesta asume que hay una red sobrecargada o un servidor SQL y, según la pregunta, no lo sabe. Si se tratara de un ataque DDoS, habría más de 100 / seg (no minuto) y no sería contra una mesa vacía.
paparazzo

Correcto, basado en la pregunta que no sabemos lo suficiente como para limitarlo, por eso estaba diciendo que estas cosas podrían ser un problema, dependiendo de las circunstancias. Y lo de DDoS fue solo una analogía, basada principalmente en la redacción de la pregunta original que implicaba que varios fueron golpeados a ese ritmo y muchos otros también, pero con menos frecuencia.
Solomon Rutzky

Considero que esta es una respuesta valiosa en el sentido de que el primer párrafo lo resume muy bien: "A menos que tenga una CPU o memoria alta en el servidor de la base de datos, esto probablemente no sea un problema". En nuestro caso, tenemos un alto uso de CPU en ciertos momentos del día y, por lo tanto, la presión adicional de la CPU parece ser un factor basado en mis pruebas.
Peter

En particular, solo cité consultas que se ejecutan 100-200 veces / minuto, cuando en realidad hay alrededor de 50 consultas en estas tablas vacías con conteos de ejecución de entre 200-4000 / minuto. Acumulativamente, el efecto de consultar tablas vacías con esta frecuencia afecta bastante a la CPU, incluso en el mejor de los casos de consultas no parametrizadas que se ejecutan repetidamente, por lo que el plan, los datos, etc. están todos en la memoria.
Peter

0

En general, en cada consulta se realizan los siguientes pasos:

  1. Solicitud de solicitud.
  2. Base de datos Analiza la consulta.
  3. El motor de base de datos verifica si esta consulta ya está almacenada en la RAM. use el plan de ejecución si existe en la memoria.
  4. si no existe en la RAM, el motor de la base de datos verifica las estadísticas existentes sobre los objetos en la consulta y determina el plan de ejecución.
  5. Ejecute el plan de ejecución, use E / S para obtener datos del disco.
  6. Respuesta a la solicitud.

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.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.