Problemas de rendimiento de SQL con consultas remotas en servidores vinculados


8

Este procedimiento

create proc dbo.Get_Accounts as
begin
  declare @current_date datetime
  set @current_date = dbo.fn_currdate()

  select [fields]
  into dbo.current_accounts
  from linkedserver.database.dbo.accounts
  where date = @current_date
end

falla continuamente después de 10 minutos con el siguiente mensaje de error:

Servidor: Msg 7399, Nivel 16, Estado 1, Línea 1 El proveedor OLE DB 'SQLOLEDB' informó un error. El proveedor finalizó la ejecución porque se alcanzó un límite de recursos. [Mensaje devuelto por el proveedor OLE / DB: Tiempo de espera expirado] Rastreo de error OLE DB [Proveedor OLE / DB 'SQLOLEDB' ICommandText :: Ejecutar devuelto 0x80040e31: Ejecución finalizada por el proveedor porque se alcanzó un límite de recursos.].

Sin embargo, cuando ejecuto la misma consulta desde la misma base de datos (no en la remota) en una ventana de consulta interactiva con la fecha codificada:

  select [fields]
  into dbo.current_accounts
  from linkedserver.database.dbo.accounts
  where date = '1/20/2012'

Regresa en 30 segundos.

El servidor local es SQLSERVER 2008, el remoto es SQLSERVER 2000.

Hemos hecho lo siguiente en vano:

  • Recrea el proceso almacenado.
  • sp_recompile en el proceso almacenado
  • actualizar estadísticas en dbo.accounts
  • cayó y recreó los índices en dbo.accounts
  • dejó caer el índice en dbo.accounts e intentó
  • DBCC FREEPROCCACHE & DBCC DROPCLEANBUFFERS en servidores locales y remotos
  • Reinició el servidor remoto (no es una opción fácil en el local)

Preguntas

  • ¿Alguien puede explicar este extraño comportamiento?
  • ¿Alguna sugerencia sobre otras opciones para corregirlo?

Respuestas:


11

Puede activar el indicador de rastreo 7300, que podría proporcionarle un mensaje de error más detallado

¿Cuántas filas devuelve una consulta representativa? ¿Qué tan rápido / confiable es la conexión de red entre los dos servidores?

Es posible que un conjunto de datos grande tarde demasiado en transferirse (además del tiempo de consulta real). Podría aumentar el valor del tiempo de espera.

Puede intentar reconfigurar la configuración del tiempo de espera de la siguiente manera:

Establezca el tiempo de espera de inicio de sesión remoto en 300 segundos:

sp_configure 'remote login timeout', 300
go 
reconfigure with override 
go 

Establezca el tiempo de espera de la consulta remota en 0 (espera infinita):

sp_configure 'remote query timeout', 0 
go 
reconfigure with override 
go 

Actualización : SQL Server 2012 SP1 en adelante : los usuarios con SELECTpermiso podrán acceder, DBCC SHOW_STATISTICSlo que mejorará el rendimiento de solo lectura en los servidores vinculados. Ref: https://msdn.microsoft.com/en-us/library/ms174384(v=sql.110).aspx

Actualización : tiene razón al decir que no es el tamaño de los datos o la velocidad de conexión. Sonó una campana en mi memoria nebulosa y recordé dónde lo había visto: lento en la aplicación, rápido en SSMS? (Un problema con los servidores vinculados). No es la detección de parámetros, son las estadísticas las que faltan (debido a los permisos), lo que hace que se use un plan de consulta incorrecto:

Puedes ver que las estimaciones son diferentes. Cuando ejecuté como sysadmin, la estimación fue de 1 fila, que es un número correcto, ya que no hay pedidos en Northwind donde el ID de la orden excede 20000. Pero cuando ejecuté como un usuario normal, la estimación fue de 249 filas. Reconocemos este número en particular como el 30% de 830 pedidos, o la estimación para una operación de desigualdad cuando el optimizador no tiene información. Anteriormente, esto se debía a un valor de variable desconocido, pero en este caso no hay una variable que pueda ser desconocida. No, son las estadísticas mismas las que faltan.

Mientras una consulta solo acceda a tablas en el servidor local, el optimizador siempre puede acceder a las estadísticas de todas las tablas en la consulta; No hay controles de permisos adicionales. Pero esto es diferente con las tablas en un servidor vinculado. Cuando SQL Server accede a un servidor vinculado, no existe un protocolo secreto que solo se use para la comunicación entre servidores. No, en cambio, SQL Server utiliza la interfaz OLE DB estándar para servidores vinculados, sean otras instancias de SQL Server, Oracle, archivos de texto o su fuente de datos elaborada en casa, y se conecta como cualquier otro usuario. Exactamente cómo se recuperan las estadísticas depende de la fuente de datos y del proveedor OLE DB en cuestión. En este caso, el proveedor es SQL Server Native Client que recupera las estadísticas en dos pasos. (Puede ver esto ejecutando Profiler en el servidor remoto). Primero, el proveedor ejecuta el procedimiento sp_table_statistics2_rowset que devuelve información sobre qué estadísticas de columna hay, así como su cardinalidad y su información de densidad. En el segundo paso, el proveedor ejecuta DBCC SHOW_STATISTICS, un comando que devuelve las estadísticas de distribución completas. (Veremos más de cerca este comando más adelante en este artículo). Aquí está el truco: para ejecutar DBCC SHOW_STATISTICS, debe ser miembro del rol de servidor sysadmin o de cualquiera de los roles de base de datos db_owner o db_ddladmin.

Y es por eso que obtuve resultados diferentes. Cuando ejecuté como sysadmin obtuve las estadísticas de distribución completas que indicaban que no hay filas con ID de pedido> 20000, y la estimación era de una fila. (Recuerde que el optimizador nunca asume cero filas de las estadísticas). Pero cuando se ejecuta como usuario normal, DBCC SHOW_STATISTICS falló con un error de permiso. Este error no se propagó, sino que el optimizador aceptó que no había estadísticas y utilizó supuestos predeterminados. Como obtuvo información de cardinalidad, se enteró de que la tabla remota tiene 830 filas, de ahí la estimación de 249 filas.

Siempre que encuentre un problema de rendimiento en el que una consulta que incluye acceso a un servidor vinculado sea lenta en la aplicación, pero se ejecuta rápidamente cuando la prueba desde SSMS, siempre debe investigar si la causa podría ser la falta de permisos en la base de datos remota. (Tenga en cuenta que el acceso al servidor vinculado puede no estar abierto en la consulta, pero podría estar oculto en una vista). Si determina que los permisos en la base de datos remota es el problema, ¿qué acciones podría tomar?

  • Puede agregar a los usuarios al rol db_ddladmin, pero dado que esto les da derecho a agregar y soltar tablas, no es recomendable.

  • De forma predeterminada, cuando los usuarios se conectan a un servidor remoto, se conectan como ellos mismos, pero puede configurar una asignación de inicio de sesión con sp_addlinkedsrvlogin, de modo que los usuarios asignen una cuenta proxy que sea miembro de db_ddladmin. Tenga en cuenta que esta cuenta de proxy debe ser un inicio de sesión de SQL, por lo que esta no es una opción si el servidor remoto no tiene habilitada la autenticación de SQL. Esta solución también es algo dudosa desde una perspectiva de seguridad, aunque es mejor la sugerencia anterior.

  • En algunos casos, puede volver a escribir la consulta con OPENQUERY para forzar la evaluación en el servidor remoto. Esto puede ser particularmente útil si la consulta incluye varias tablas remotas. (Pero también puede ser contraproducente, porque el optimizador ahora obtiene aún menos información estadística del servidor remoto).

  • Por supuesto, puede usar la batería completa de sugerencias y guías de plan para obtener el plan que desea.

  • Finalmente, debe preguntarse si se necesita ese acceso de servidor vinculado. ¿Quizás las bases de datos podrían estar en el mismo servidor? ¿Se podrían replicar los datos? Alguna otra solucion?


Devuelve alrededor de 140k registros. pero dado que funciona bien cuando el valor de la fecha está codificado, no puedo pensar en un problema de E / S o de red que afectaría la versión parametrizada tan extremadamente. Mi instinto dice que la consulta se pasa al servidor remoto y el optimizador remoto elige de alguna manera un plan de consulta incorrecto cuando no puede entender el parámetro. Pero reindexar y purgar el caché / buffers debería corregir eso (supongo). Revisaré los tiempos de espera para ver si podemos lograr que al menos regrese. Gracias

1
Excelente respuesta y explicó exactamente el problema que estaba teniendo, gracias. Agregaría que según el MSDN , a partir de SQL2012 SP1 en adelante, los usuarios con SELECTpermiso podrán acceder, DBCC SHOW_STATISTICSlo que mejorará el rendimiento de solo lectura en los servidores vinculados sin comprometer la seguridad.
Steve Pettifer

2

¿Qué sucede cuando intenta esto (es decir, indique explícitamente qué se debe ejecutar en el servidor remoto) ?:

select [fields]
into dbo.current_accounts
from OPENQUERY(linkedserver, 'SELECT [fields] FROM database.dbo.accounts where date = ''1/20/2012''');

Sospecho que en su caso anterior, SQL Server simplemente extrae toda la tabla del servidor remoto y luego ejecuta la consulta localmente (he visto que esto sucedió muchas veces en el pasado). Prefiero ser explícito (ya sea usando OPENQUERY o creando un SP en el servidor remoto) para que no haya posibilidad de confusión.


1

Como se trata de un problema de recursos, el grupo de memoria fuera del servidor SQL utilizado para cargar controladores externos y el CLR podría estar cerca de su límite. El valor predeterminado es 256 MB. Para evitar esto, sugiero que vaya al administrador de configuración del servidor SQL, a la pestaña avanzada y agregue la opción -g al final de los parámetros de inicio.ie; -g1024 luego reinicie el servicio SQL Server. Por lo general, hago esto ya que usamos una gran cantidad de servidores vinculados. http://msdn.microsoft.com/en-us/library/ms190737.aspx


1

Tengo dos ideas que pueden ayudar. También le diré que me he mezclado con la mala suerte con el rendimiento al ejecutar consultas en servidores vinculados. Así que mi primera recomendación es evitarlo si puedes.

Mi primera idea es instalar el procedimiento almacenado en el cuadro SQL Server 2000, haciendo referencia al servidor local. Luego puede ejecutar el procedimiento almacenado de forma remota.

exec linkedserver.database.dbo.Get_Accounts

Si puede seguir esta ruta, debería mejorar enormemente el rendimiento.

Mi segunda idea es llegar al plan de consulta estimado al ejecutar el procedimiento almacenado. ¿Te está mostrando lo que está tomando tanto tiempo? Un problema potencial es que la cuenta que está utilizando en el servidor vinculado podría no tener suficiente autoridad para acceder a las estadísticas de la tabla (necesita más autoridad para el servidor vinculado que para el servidor local). Y eso puede hacer que las consultas sean increíblemente lentas. Puede leer más sobre ese problema en particular aquí .

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.