2009-06-13 12 views
9

Estoy escribiendo un código de registro/auditoría que se ejecutará en producción (no solo cuando se producen errores o durante el desarrollo). Después de leer Coding Horror's experiences with dead-locking and logging, decidí que debería buscar consejo. (La solución de Jeff de "no iniciar sesión" no funcionará para mí, esta es una auditoría de seguridad ordenada por ley)Consejos para minimizar el bloqueo en una tabla de solo agregar en MS SQL Server?

¿Hay un nivel de aislamiento adecuado para minimizar la contención y el bloqueo muerto? ¿Alguna sugerencia de consulta que pueda agregar a la declaración de inserción o al procedimiento almacenado?

Me preocupa profundamente la integridad transaccional de todo excepto la tabla de auditoría. La idea es que se registrará tanto que si fallan algunas entradas, no es un problema. Si el registro detiene alguna otra transacción, sería malo.

Puedo iniciar sesión en una base de datos o en un archivo, aunque el registro en un archivo es menos atractivo porque necesito poder mostrar los resultados de alguna manera. El registro en un archivo (casi) garantizaría que el registro no interferiría con otro código.

+0

¿qué versión del servidor sql? –

+0

SQL 2000, aunque hay rumores de que algún día la oficina saltará a SQL 2008. – MatthewMartin

Respuesta

5

Una inserción de transacción normal (es decir, READ COMMITTED) ya hace el bloqueo 'mínimo'. Las aplicaciones intensivas de inserción no bloquearán la inserción, sin importar el orden en que la inserción se mezcle con otras operaciones. En el peor de los casos, un sistema de inserción intensivo puede causar una contención de enganche de página en el punto caliente donde ocurre la inserción, pero no interbloqueos.

Para hacer que los puntos muertos como se describe por Jeff tiene que haber más en juego, como cualquiera de los siguientes:

  • el sistema está utilizando un nivel de aislamiento superior (tenían venir a continuación, y así se lo merecen)
  • estaban leyendo desde la tabla de registro durante la transacción (por lo que ya no 'solo-agregar')
  • la cadena de interbloqueo involucrado cerraduras de capa de aplicación (es decir. .Net lock declaraciones en el marco log4net) resultando en indetectable es deadlocks (es decir, la aplicación se cuelga). Dado que resolver el problema involucrado mirando los vertederos de procesos, creo que este es el escenario que estaban teniendo.

Por lo tanto, siempre y cuando inserte solo el registro en las transacciones de nivel de aislamiento LEÍDO COMPROMETIDO, estará seguro. Si espera el mismo problema que sospecho que SO (es decir, interbloqueos que implican bloqueos de capa de aplicación), no puede ahorrarle nada de la magia de la base de datos, ya que el problema puede manifestarse incluso si inicia sesión en una transacción separada o en una conexión separada.

+1

"Por lo tanto, siempre que inserte solo el inicio de sesión en las transacciones de nivel de aislamiento LEÍDO COMPROMETIDO, estará seguro". Esto no es verdad. Si está participando en una transacción grande, puede bloquear toda la transacción cuando intente insertar cosas en la tabla de registro (si la tabla de registro está bloqueada porque está ejecutando algún informe descabellado o algo así). ¡También esto te abre a la central de interbloqueo! –

+2

No, simplemente no es cierto. INSERT bloqueará * no * detrás de un informe (leído confirmado), sin importar lo que haga en la transacción. Además, los INSERTOS concurrentes nunca aparecerán en una cadena de interbloqueo, nuevamente porque no se bloquean uno detrás de otro ni detrás de SELECT. Las cosas que pueden bloquear una inserción son: un bloqueo S de rango que cubre el punto de inserción (es decir, un informe serializable), un bloqueo S en la tabla (es decir, escalamiento de un informe repetible) o bloqueos X (es decir, alguna actividad * otra * que 'solo anexar', como actualizaciones que escalaron al bloqueo de la tabla X). –

+2

INSERTAR en una tabla (con un índice agrupado) en confirmación de lectura adquiere un bloqueo IX en la página yy X bloquea la tecla. Si no puede adquirir el bloqueo IX en la página, esperará, si no puede adquirir y X bloqueará la tecla, esperará. Las instrucciones SELECT necesitan bloqueos compartidos. Los bloqueos pueden entrar en conflicto. Los bloqueos pueden existir. Lea: http://msdn.microsoft.com/en-us/library/ms186396.aspx –

1

Dado que no le importa la integridad transaccional de la tabla de auditoría, obviamente puede realizar el registro fuera de la transacción (es decir, una vez que se complete). Eso minimizará el impacto en la transacción.

Además, si desea minimizar el bloqueo, debe asegurarse de que la mayor parte posible de la carga de trabajo de la consulta cubra los índices no agrupados. (SQL Server 2005 y superior, el uso de la declaración INCLUDE en índices NC puede hacer una gran diferencia)

+0

Nota: si realiza todo el registro una vez que se completa una transacción, es bastante difícil depurar transacciones de larga ejecución o transacciones canceladas. –

+0

El póster ya dejó en claro que no importa si el registro falla, siempre que se complete una transacción. Obviamente, las transacciones deben ser lo más cortas posible. –

+0

Todo lo que digo es que en este contexto (es decir, en un hilo separado) es probablemente mejor que (es decir, después de que se completa) –

1

Una manera fácil de evitar que su registro tenga problemas de bloqueo con su base de datos 'regular' es no usar la misma base de datos . Simplemente crea otra base de datos para tu registro. Como beneficio adicional, el rápido crecimiento de su base de datos de registro no generará fragmentación en su base de datos principal. Personall, generalmente prefiero iniciar sesión en un archivo, pero de nuevo, estoy acostumbrado a manipular textos pesados ​​en mi editor - VIM. Iniciar sesión en un DB separado debería ayudar a evitar problemas de bloqueo.

Solo asegúrate de que si intentas escribir tu propio appender de base de datos para el marco de trabajo de registro que usas, ten mucho cuidado con tus bloqueos (que supongo que fue lo que hizo tropezar a Jeff en la publicación del blog que haces referencia). Correctamente escrito (vea varios de los comentarios en la publicación de Jeff), no debería tener problemas de bloqueo con su marco de trabajo de registro a menos que hagan algo impar.

+0

Creo que introducir una base de datos completamente nueva solo para una tabla de registro es bastante agresiva, siempre puedes controlar la ubicación de almacenamiento de cada tabla usando grupos de archivos si es necesario de todos modos. Además, si usted ha distribuido la transacción en su lugar, entonces el registro en una base de datos independiente puede empeorar las cosas si esa operación participa en la transacción distribuida. –

+0

Si está utilizando transacciones distribuidas, le aconsejaría * no * tener su registro alistado en ellas. No hay nada como romper algo que provoque una reversión de transacción y no tener ningún registro de lo que se rompió ... –

5

Si no se preocupan por la consistencia en su tabla de registro, ¿por qué no realiza todo el registro de un hilo separado.

Probablemente no esperaría a que se completaran las transacciones antes de iniciar sesión, ya que el registro puede ser fundamental para diagnosticar transacciones de larga ejecución. Además, esto le permite ver todo el trabajo realizado por una transacción que retrocedió.

Tome el seguimiento de la pila y todos sus datos de registro en la cadena de registro, chuck it on a queue cuando haya nuevos mensajes de registro, vacíelos a la base de datos en una sola transacción.

pasos para bloqueo minimizando:

  • (KEY) realizar todas añade a la tabla de registro fuera del hilo principal/conexión/transacción.
  • Asegúrese de que su tabla de registro tenga un índice agrupado monótonamente creciente (por ejemplo, identidad int) que se incrementa cada vez que anexa un mensaje de registro. Esto garantiza que las páginas que se inserten usualmente se encuentren en la memoria y evite los golpes de rendimiento que se obtienen con las tablas de montón.
  • Realizar múltiples agrega al registro en una transacción (10 inserciones en una transacción son más rápidas que 10 inserciones de una transacción y generalmente adquieren/liberan menos bloqueos)
  • Dale un respiro. Solo realice el registro en su db cada N milisegundos. Alinee bits de trabajos.
  • Si necesita informar algo históricamente, puede considerar particionar su tabla de registro. Ejemplo: Puede crear una nueva tabla de registro cada mes y, al mismo tiempo, tener un registro VER que es una UNIÓN TODAS las tablas de registro anteriores. Realice los informes contra la fuente más apropiada.

Va a obtener un mejor rendimiento por el lavado de múltiples mensajes de registro en una sola transacción (pequeña), y tienen la ventaja de que si 10 hilos están haciendo el trabajo y la explotación forestal cosas, sólo un único flujo está volcando cosas a la mesa de registro . Esta canalización realmente hace que las cosas escalen mejor.

Cuestiones relacionadas