Encontrar Tablelocks/Deadlocks en Navision & Business Central

Nav123: Navision, Showare, OrderApp

Print Friendly, PDF & Email

¿Qué son los "tablelocks"?

Tablelocks = bloqueos de tabla...

...no son nada malo para empezar. Todas las bases de datos las utilizan para garantizar la integridad de los datos.

Un ejemplo: El usuario A tiene un registro maestro de cliente en la pantalla y ahora cambia la calle. Este proceso se guarda ahora en la base de datos para que la nueva calle quede guardada de forma permanente. El usuario B está editando el mismo registro de datos y quiere cambiar el número de teléfono. En realidad, ambas acciones pueden realizarse independientemente la una de la otra.

Sin embargo, como el cambio realizado por el usuario A siempre vuelve a escribir todo el registro de datos y el cambio de número de teléfono realizado por el usuario B también vuelve a escribir todo el registro del cliente (incl. nombre, dirección, calle, nuevo número de teléfono, límite de crédito, etc.), en este caso puede ocurrir lo siguiente: El usuario A y el usuario B reciben en pantalla el mismo registro con la antigua dirección y el antiguo número de teléfono.

El usuario A ahora sólo cambia la dirección (el número de teléfono no) y guarda este registro. El usuario B no se ha dado cuenta. Sigue teniendo el registro de datos sin modificación con la antigua dirección y ahora cambia el número de teléfono. Ahora también vuelve a guardar su registro.

¿Cuál es la consecuencia? Su cambio transfiere ahora el nuevo número de teléfono.... junto con la antigua dirección a la base de datos. La corrección de A se pierde.

¿Cómo se puede evitar una situación tan cotidiana? Usted trabaja con bloqueos de tablas: El usuario A recibe el registro de datos en la pantalla. En ese momento, Navision o Business Central bloquea el registro de datos para modificaciones. Está "bloqueado". No debe confundirse con un registro de acceso, pues entonces se "registra" (del término "libro deregistro").

Ahora, el usuario B no puede visualizar en absoluto este registro de datos. Sólo cuando A termina, por ejemplo, de ver o cambiar la dirección de la calle, B recibe el registro en la pantalla, que ahora se ha liberado de nuevo. Ahora el juego vuelve a empezar.

¿Qué causa los bloqueos de tablas?


"Leer" NUNCA es un problema en Navision o Business Central. Sólo cuando se escribe empiezan los problemas. Borrar, insertar y modificar entran dentro de la categoría "escribir" (=modificar).

Afortunadamente, Business Central y Navision son mucho más inteligentes que muchos sistemas de bases de datos, que en realidad hacen esto como se ha descrito anteriormente. Navision utiliza la concurrencia optimista: en la gran mayoría de los casos, un registro de datos sólo se visualiza y no se modifica.

¿Y si se cambia una dirección? Estadísticamente, es muy poco probable que el mismo registro de datos ¿Y si se cambia una dirección? Estadísticamente, es muy poco probable que el mismo registro de datos se modifique al mismo tiempo en otro ordenador. Por este motivo, Navision no borra este registro de datos en ningún caso, sino que utiliza la marca de tiempo para comprobar si el registro de datos de la base de datos sigue siendo la misma versión que el registro de datos que se acaba de guardar para modificarlo.

Esto se hace a través del campo invisible Timestamp en cada registro de una base de datos Business Central & Navision. Por lo tanto, no puede crear usted mismo un campo llamado TimeStamp. "En el pasado" esto todavía era posible, un error "canoso" muy popular al transferir una base de datos nativa a SQL.

Entonces, si Navision no hace bloqueos, ¿cuál es el problema? El ejemplo anterior es uno de los cientos en los que los desarrolladores de Navision han aliviado al usuario de ese trabajo. Pero también hay casos reales en los que la base de datos debe estar segura de que se encuentra en un estado coherente.

Escribir duele...

Un nuevo ejemplo: un usuario reserva un pedido. Esto puede tardar 1-2 segundos. Durante este tiempo, se escriben partidas de mayor, se contabilizan albaranes y facturas, se abren partidas de cliente...

Al mismo tiempo, otro usuario podría querer borrar este pedido o incluso este cliente. Si esto se permitiera, acabarían existiendo albaranes, partidas abiertas y facturas para un cliente que ya no existía en ese momento. Dependiendo del cambio de hora, ¡ni siquiera habría habido artículos en el cliente que hubieran prohibido la eliminación!

Business Central y Navision se esfuerzan mucho más por evitar esto, pero es suficiente para nuestro ejemplo.
Navision bloquea ("lock") el pedido y el cliente al contabilizar para evitar exactamente esta situación. Esto se hace de otra manera realmente, pero eso no es tan importante aquí.
Así que ahora hay algunas tablas que están bloqueadas ("abiertas a escritura") durante un breve periodo de tiempo: Pedidos, líneas de pedido, cabeceras de albarán reservado, líneas de albarán reservado... y algunas más.

Si no hay mucha gente trabajando en el sistema, esto no supone ningún problema: al fin y al cabo, estas tablas vuelven a estar libres uno o dos segundos después. (¿No es su caso? ¿Tardas muchos segundos o incluso minutos en publicar un pedido? ¡Eso sí que es malo! Esto sí que puede acelerarse.)

Entonces, ¿aún no hay problema? Exacto. A menos que... esas transacciones tarden demasiado, o bloqueen tablas en secuencias diferentes. Esto es exactamente por lo que ocurren los bloqueos.

Deadlocks... la vista de las puertas del infierno

Deadlocks: Supongamos que un programa quiere bloquear deudores para introducir después pedidos para ellos. Primero BUSINESS CENTRAL o NAVISION bloquean los clientes, después... hay un momento de retraso. Durante este tiempo, se inicia otro programa, que bloquea los pedidos y, si es necesario, realiza cambios de datos en el cliente.

Ahora, el primer programa también quiere bloquear los pedidos de sus clientes. Esto no es posible porque el segundo programa ya ha bloqueado los pedidos para sí mismo. Así que el primer programa simplemente espera a poder bloquear también los pedidos. Realmente espera. El segundo programa llega al punto en el que quiere cambiar los clientes, es decir, bloquearlos también. Solicita el bloqueo de clientes a la base de datos... ¡pero ya están bloqueados!

Ahora se produce un deadlock: ambos programas esperan la otra tabla bloqueada por el otro programa. El bloqueo es, en principio, infinito, ya que ambos programas esperan a que se libere la otra tabla del primer programa. Esta situación se conoce como "punto muerto": nunca se libera por sí solo.

El servidor SQL lo reconoce y termina una de las dos consultas para que la otra pueda seguir funcionando.

Regla de oro: Cuanto peor es el código del programa, más largo es el procesamiento del programa y más probables son los bloqueos. Simplemente porque los bloqueos de escritura están activos durante demasiado tiempo. Por lo tanto, la optimización del rendimiento también consiste en evitar los bloqueos.

Encontrar tablelocks/deadlocks

En Navision o Business Central, un bloqueo resuelto sólo se muestra con un simple mensaje de error:

"No se ha podido completar el proceso porque un registro de datos de la tabla "xxx" estaba bloqueado por otro usuario". Vuelva a ejecutar la acción. Este mensaje aparece siempre en el ordenador que ha perdido el deadlock.

Ocasionalmente, sin embargo, los bloqueos se distribuyen entre varios programas, de modo que ni siquiera el propio servidor (SQL) puede determinar que se trata de un bloqueo. Aquí es donde entra en juego, por ejemplo, el tiempo máximo de ejecución de SQL.

Hasta Navision 2009R2, bastaba con mirar en la tabla de sesiones para ver qué proceso estaba bloqueando al otro. Con un rápido vistazo a la pantalla derecha, se podía localizar rápidamente el problema... o iniciar una búsqueda exhaustiva.

Sin embargo, desde Navision & Business Central 2013 RTC, la política de Microsoft de hacerlo todo más complicado y más difícil siempre que sea posible ha surtido efecto. Aquí hay que desahogarse directamente en el servidor SQL. He aquí algunos métodos de análisis:

Siempre se inicia en el servidor SQL en la base de datos actual con una consulta

Auflisten von blockierenden Usern

exec sp_who2

SQL enumera todas las sesiones. Una sesión bloqueada muestra en la columna "Blkby" si/por qué sesión está bloqueada.
Por regla general, encontrará el mismo identificador de sesión en varias sesiones que esperan la misma sesión de bloqueo.

Si lo desea, puede ir un nivel más allá con los objetos bloqueados. La lista resultante es mucho más clara, pero quizás no suficiente. Especialmente si ha tenido mucho cuidado de escribir sólo en tablas temporales antes de un Page.runmodal, y un desagradable mensaje de error sigue indicando una tabla bloqueada, le costará averiguar qué tabla(s) está(n) bloqueada(s)... Esto a menudo te ayuda a ponerte en el camino correcto.

Microsoft Dynamics 365 Business CentralDie unten aufgeführten C/AL-Funktionen sind während Schreibtransaktionen eingeschränkt, da mindestens eine Tabelle gesperrt wird. Form.RunModal ist in Schreibtransaktionen nicht zulässig. Codeunit.Run ist in Schreibtransaktionen nur zulässig, wenn der Rückgabewert nicht verwendet wird. OK := Codeunit.Run() ist z. B. nicht zulässig. Report.RunModal ist in Schreibtransaktionen nur zulässig, wenn RequestForm = FALSE. Report.RunModal(...,FALSE) ist z. B. zulässig. XmlPort.RunModal ist in Schreibtransaktionen nur zulässig, wenn RequestForm = FALSE gilt. XmlPort.RunModal(...,FALSE) ist z. B. zulässig. Verwenden Sie die COMMIT-Funktion, um die Änderungen vor dem Aufruf zu speichern, oder strukturieren Sie den Code anders.

Microsoft Dynamics 365 Business Central

Contenido del mensaje de error: Las funciones C/AL enumeradas a continuación están restringidas durante las transacciones de escritura porque al menos una tabla está bloqueada. Form.RunModal no está permitida en las transacciones de escritura. Codeunit.Run sólo se permite en transacciones de escritura si no se utiliza el valor de retorno. OK := Codeunit.Run() no está permitido, por ejemplo. Report.RunModal sólo se permite en transacciones de escritura si RequestForm = FALSE. Report.RunModal(...,FALSE) está permitido, por ejemplo. XmlPort.RunModal sólo se permite en transacciones de escritura si RequestForm = FALSE. XmlPort.RunModal(...,FALSE) está permitido, por ejemplo. Utilice la función COMMIT para guardar los cambios antes de la llamada, o estructure el código de otra manera.

-- List all Locks of the Current Database  Source: https://stackoverflow.com/questions/694581/how-to-check-which-locks-are-held-on-a-table
SELECT TL.resource_type AS ResType 
      ,TL.resource_description AS ResDescr 
      ,TL.request_mode AS ReqMode 
      ,TL.request_type AS ReqType 
      ,TL.request_status AS ReqStatus 
      ,TL.request_owner_type AS ReqOwnerType 
      ,TAT.[name] AS TransName 
      ,TAT.transaction_begin_time AS TransBegin 
      ,DATEDIFF(ss, TAT.transaction_begin_time, GETDATE()) AS TransDura 
      ,ES.session_id AS S_Id 
      ,ES.login_name AS LoginName 
      ,COALESCE(OBJ.name, PAROBJ.name) AS ObjectName 
      ,PARIDX.name AS IndexName 
      ,ES.host_name AS HostName 
      ,ES.program_name AS ProgramName 
FROM sys.dm_tran_locks AS TL 
     INNER JOIN sys.dm_exec_sessions AS ES 
         ON TL.request_session_id = ES.session_id 
     LEFT JOIN sys.dm_tran_active_transactions AS TAT 
         ON TL.request_owner_id = TAT.transaction_id 
            AND TL.request_owner_type = 'TRANSACTION' 
     LEFT JOIN sys.objects AS OBJ 
         ON TL.resource_associated_entity_id = OBJ.object_id 
            AND TL.resource_type = 'OBJECT' 
     LEFT JOIN sys.partitions AS PAR 
         ON TL.resource_associated_entity_id = PAR.hobt_id 
            AND TL.resource_type IN ('PAGE', 'KEY', 'RID', 'HOBT') 
     LEFT JOIN sys.objects AS PAROBJ 
         ON PAR.object_id = PAROBJ.object_id 
     LEFT JOIN sys.indexes AS PARIDX 
         ON PAR.object_id = PARIDX.object_id 
            AND PAR.index_id = PARIDX.index_id 
WHERE TL.resource_database_id  = DB_ID() 
      AND ES.session_id <> @@Spid -- Exclude "my" session 
      -- optional filter  
      AND TL.request_mode <> 'S' -- Exclude simple shared locks 
ORDER BY TL.resource_type 
        ,TL.request_mode 
        ,TL.request_type 
        ,TL.request_status 
        ,ObjectName 
        ,ES.login_name;



--TSQL commands
SELECT 
       db_name(rsc_dbid) AS 'DATABASE_NAME',
       case rsc_type when 1 then 'null'
                             when 2 then 'DATABASE' 
                             WHEN 3 THEN 'FILE'
                             WHEN 4 THEN 'INDEX'
                             WHEN 5 THEN 'TABLE'
                             WHEN 6 THEN 'PAGE'
                             WHEN 7 THEN 'KEY'
                             WHEN 8 THEN 'EXTEND'
                             WHEN 9 THEN 'RID ( ROW ID)'
                             WHEN 10 THEN 'APPLICATION' end  AS 'REQUEST_TYPE',

       CASE req_ownertype WHEN 1 THEN 'TRANSACTION'
                                     WHEN 2 THEN 'CURSOR'
                                     WHEN 3 THEN 'SESSION'
                                     WHEN 4 THEN 'ExSESSION' END AS 'REQUEST_OWNERTYPE',

       OBJECT_NAME(rsc_objid ,rsc_dbid) AS 'OBJECT_NAME', 
       PROCESS.HOSTNAME , 
       PROCESS.program_name , 
       PROCESS.nt_domain , 
       PROCESS.nt_username , 
       PROCESS.program_name ,
       SQLTEXT.text 
FROM sys.syslockinfo LOCK JOIN 
     sys.sysprocesses PROCESS
  ON LOCK.req_spid = PROCESS.spid
CROSS APPLY sys.dm_exec_sql_text(PROCESS.SQL_HANDLE) SQLTEXT
where 1=1
and db_name(rsc_dbid) = db_name()



--Lock on a specific object
SELECT * 
FROM sys.dm_tran_locks
WHERE resource_database_id = DB_ID()
AND resource_associated_entity_id = object_id('Specific Table');

Carga de la base de datos

Como los bloqueos prácticamente siempre van de la mano de tiempos de ejecución del programa excesivamente largos, y éstos casi siempre están causados por consultas a la base de datos mal planteadas, siempre es útil echar un vistazo a la carga de la base de datos:

select spid,cmd,waittime,lastwaittype,cpu,physical_io,login_time,last_batch,status,hostname,program_name,nt_username, nt_domain
from master.dbo.sysprocesses where dbid = db_id(‚BaseDeDatosDeseada‘)

o

SELECT DISTINCT
name AS database_name,
session_id,
host_name,
login_time,
login_name,
reads,
writes
FROM sys.dm_exec_sessions
LEFT OUTER JOIN sys.dm_tran_locks ON sys.dm_exec_sessions.session_id = sys.dm_tran_locks.request_session_id
INNER JOIN sys.databases ON sys.dm_tran_locks.resource_database_id = sys.databases.database_id
WHERE resource_type <> ‚DATABASE‘
–AND request_mode LIKE ‚%X%‘
–AND name =’BaseDeDatosInteresada‘
ORDER BY name

Mientras que las lecturas y escrituras en el rango de 5 dígitos no suelen ser dignas de atención, deberías echar un vistazo a los accesos de 6 dígitos, y las campanas de alarma deberían sonar en los accesos de 7 dígitos... dependiendo del tiempo de ejecución previo del proceso respectivo, por supuesto.

1,5 millones de accesos de escritura para un Conector EDIfact que ha estado en línea durante 12 días es un número diferente que 500.000 accesos de lectura para un usuario que se ha conectado hace 5 minutos. Performance Troubleshooting necesita experiencia y paciencia.

En Business Central y Navision Debugger desde 2017

Aquí ya se ha incorporado la supervisión del bloqueo en el depurador. Sin embargo, Navision o Business Central requieren cambios en el servidor SQL para que también libere los datos necesarios.

Si Business Central o el propio Navision han instalado el servidor, estos ajustes ya se habrán realizado.

Realice los ajustes en SQL_Server, si no lo ha hecho ya:
En Servidor MSSMS/Propiedades -> Autorizaciones, para el login bajo el que se está ejecutando el servicio Navision:
Cambiar cualquier sesión de eventos: Conceder.
Mostrar el estado del servidor: Conceder.

Asigne este usuario a la base de datos deseada como propietario a través de Servidor/Seguridad/Inicio de sesión.
Active la supervisión del bloqueo en los ajustes de Business Central y Navision:

El monitor de actividad también puede ser útil para solucionar problemas de rendimiento. Se puede acceder a él a través del MSSMS:

He aquí algunas herramientas más del monitor de actividad