sql server - tipo - ¿Las tablas temporales son seguras para hilos?
tablas temporales vs variables tipo tabla sql server (9)
Las tablas temporales de alcance local (con un único #) se crean con un identificador al final que las hace únicas; múltiples llamadores (incluso con el mismo inicio de sesión) nunca deben superponerse.
(Pruébalo: crea la misma tabla temporal a partir de dos conexiones y el mismo inicio de sesión. Luego consulta tempdb.dbo.sysobjects para ver las tablas reales creadas ...)
Estoy usando SQL Server 2000, y muchos de los procedimientos almacenados usan extensas tablas temporales. La base de datos tiene mucho tráfico, y me preocupa la seguridad de la ejecución de subprocesos de tablas temporales.
Digamos que tengo un procedimiento almacenado que crea algunas tablas temporales, incluso puede unir tablas temporales a otras tablas temporales, etc. Y también podemos decir que dos usuarios ejecutan el procedimiento almacenado al mismo tiempo.
¿Es posible que un usuario ejecute sp y cree una tabla temporal llamada #temp, y el otro usuario ejecute el mismo sp pero se detiene porque una tabla llamada #temp ya existe en la base de datos?
¿Qué tal si el mismo usuario ejecuta el mismo procedimiento almacenado dos veces en la misma conexión?
¿Hay algún otro escenario extraño que pueda causar que dos consultas de usuarios interfieran entre sí?
Las tablas temporales están vinculadas a la sesión, por lo que si diferentes usuarios ejecutan su procedimiento simultáneamente, no hay conflicto ...
Las tablas temporales se crean solo en el contexto de la consulta o el proceso que las crea. Cada nueva consulta obtiene un contexto en la base de datos que está libre de otras tablas temporales de consultas. Como tal, la colisión del nombre no es un problema.
Primero asegurémonos de que está utilizando tablas temporales reales, ¿comienzan con # o ##? Si está creando tablas reales sobre la marcha y luego las descarta y recrea repetidas veces, de hecho tendrá problemas con los usuarios concurrentes. Si está creando tablas temporales globales (las que comienzan con ##) también puede tener problemas. Si no desea problemas de simultaneidad, use tablas temporales locales (Comienzan con #). También es una buena práctica cerrarlos explícitamente al final del proceso (o cuando el proceso ya no los necesita, si está hablando de procesos largos de pasos múltiples) y verificar la existencia (y soltarlos si es así) antes de crearlos. .
Si busca en la base de datos de temps, puede ver las tablas temporales allí, y tienen nombres generados por el sistema. Entonces, aparte de los bloqueos regulares, debería estar bien.
a menos que use dos signos de libra ## temp, la tabla temporal será local y solo existe para esa conexión local con el usuario
Para el primer caso, no, no es posible, porque #temp es una tabla temporal local y, por lo tanto, no visible para otras conexiones (se supone que los usuarios están usando conexiones de bases de datos separadas). El nombre de la tabla temporal se alias a un nombre aleatorio que se genera y usted hace referencia a eso cuando hace referencia a su tabla temporal local.
En su caso, dado que está creando una tabla temporal local en un procedimiento almacenado, esa tabla temporal se eliminará cuando se salga del alcance del procedimiento (consulte la "sección de comentarios").
Para el segundo caso, sí, obtendrá este error, porque la tabla ya existe y la tabla dura tanto como la conexión. Si este es el caso, le recomiendo que compruebe la existencia de la tabla antes de intentar crearla.
Las tablas temporales locales son seguras para subprocesos, porque solo existen dentro del contexto actual. No confunda el contexto con la conexión actual (desde MSDN : "Una tabla temporal local creada en un procedimiento almacenado se elimina automáticamente cuando finaliza el procedimiento almacenado"), la misma conexión puede llamar de manera segura dos o más veces un procedimiento almacenado que crea una tabla temporal local (como #TMP
).
Puede probar este comportamiento ejecutando el siguiente procedimiento almacenado desde dos conexiones. Este SP esperará 30 segundos para que podamos estar seguros de que los dos subprocesos ejecutarán sus propias versiones de la tabla #TMP al mismo tiempo:
CREATE PROCEDURE myProc(@n INT)
AS BEGIN
RAISERROR(''running with (%d)'', 0, 1, @n);
CREATE TABLE #TMP(n INT);
INSERT #TMP VALUES(@n);
INSERT #TMP VALUES(@n * 10);
INSERT #TMP VALUES(@n * 100);
WAITFOR DELAY ''00:00:30'';
SELECT * FROM #TMP;
END;
La respuesta corta es:
El aislamiento de tablas temporales está garantizado por consulta , y no hay nada de qué preocuparse, ya sea con respecto a enhebrar, bloquear o acceder concurrentemente.
No estoy seguro de por qué las respuestas aquí hablan sobre la importancia de las "conexiones" y los hilos, ya que estos son conceptos de programación, mientras que el aislamiento de las consultas se maneja a nivel de la base de datos .
Los objetos temporales locales están separados por Session en el servidor SQL. Si tiene dos consultas ejecutándose simultáneamente, entonces son dos sesiones completamente separadas y no interfieren entre sí. El inicio de sesión no importa, por lo que, por ejemplo, si está utilizando una única cadena de conexión con ADO.NET (lo que significa que varias consultas simultáneas utilizarán el mismo "inicio de sesión" de servidor SQL), sus consultas se ejecutarán en sesiones separadas . La agrupación de conexiones tampoco importa. Los objetos temporales locales (tablas y procedimientos almacenados) están completamente a salvo de ser vistos por otras sesiones .
Para aclarar cómo funciona esto; mientras que su código tiene un único nombre común para los objetos temporales locales, SQL Server agrega una cadena única a cada objeto por cada sesión para mantenerlos separados. Puede ver esto ejecutando lo siguiente en SSMS:
CREATE TABLE #T (Col1 INT)
SELECT * FROM tempdb.sys.tables WHERE [name] LIKE N''#T%'';
Verá algo como lo siguiente para el nombre:
T_______________00000000001F
Luego, sin cerrar esa pestaña de consulta, abra una nueva pestaña de consulta y pegue esa misma consulta y ejecútela nuevamente. Ahora debería ver algo como lo siguiente:
T_______________00000000001F
T_______________000000000020
Por lo tanto, cada vez que su código hace referencia a #T, SQL Server lo traducirá al nombre correcto en función de la sesión. La separación se maneja de manera auto-mágica.