Являются ли временные таблицы потокобезопасными?

Я использую SQL Server 2000, и многие хранимые процедуры в нем широко используют временные таблицы. База данных имеет большой трафик, и меня беспокоит безопасность потоков при создании и удалении временных таблиц.

Допустим, у меня есть хранимая процедура, которая создает несколько временных таблиц, она может даже присоединять временные таблицы к другим временным таблицам и т. Д. А также допустим, что два пользователя выполняют хранимую процедуру одновременно.

  • Может ли один пользователь запустить sp и создать временную таблицу с именем #temp, а другой пользователь запустит тот же sp, но будет остановлен, потому что таблица с именем #temp уже существует в базе данных?

  • Как насчет того, чтобы один и тот же пользователь дважды выполнял одну и ту же хранимую процедуру в одном и том же соединении?

  • Существуют ли какие-либо другие странные сценарии, из-за которых запросы двух пользователей могут мешать друг другу?


person Juliet    schedule 21.01.2009    source источник


Ответы (9)


В первом случае нет, это невозможно, потому что #temp - это локальная временная таблица и поэтому не видна для других подключений (предполагается, что ваши пользователи используют отдельные подключения к базе данных). Имя временной таблицы совпадает со случайным именем, которое создается, и вы ссылаетесь на него, когда ссылаетесь на свою локальную временную таблицу.

В вашем случае, поскольку вы создаете локальную временную таблицу в хранимой процедуре, эта временная таблица будет удалена при выходе из области действия процедуры (см. раздел примечаний).

Локальная временная таблица, созданная в хранимой процедуре, автоматически удаляется после завершения хранимой процедуры. На таблицу могут ссылаться любые вложенные хранимые процедуры, выполняемые хранимой процедурой, создавшей таблицу. На таблицу не может ссылаться процесс, который вызвал хранимую процедуру, создавшую таблицу.

Во втором случае да, вы получите эту ошибку, потому что таблица уже существует, и таблица существует до тех пор, пока существует соединение. В этом случае я рекомендую вам проверить наличие таблицы, прежде чем пытаться ее создать.

person casperOne    schedule 21.01.2009
comment
как вы можете выполнить одну и ту же процедуру параллельно из одного соединения? - person SQLMenace; 22.01.2009
comment
Вы можете выполнить один и тот же процесс дважды в одном и том же соединении (не параллельно) и не отбрасывать временную таблицу после первого запуска sproc. В этом случае временная таблица все еще существует. - person Jeroen Landheer; 22.01.2009
comment
Извините, @CasperOne, но ваша информация неточна: временные таблицы, созданные внутри хранимой процедуры, автоматически удаляются после завершения SP. Нет проблем с вызовом таких SP дважды по одному и тому же соединению. - person Gerardo Lima; 08.05.2012
comment
@GerardoLima Обновил ответ, чтобы отразить ваш комментарий со ссылкой на документацию. - person casperOne; 08.05.2012

Временные таблицы локальной области (с одним символом #) создаются с идентификатором в конце, который делает их уникальными; несколько абонентов (даже с одним и тем же логином) никогда не должны пересекаться.

(Попробуйте: создайте одну и ту же временную таблицу из двух подключений и одного и того же входа в систему. Затем запросите tempdb.dbo.sysobjects, чтобы увидеть фактические созданные таблицы ...)

person Joe    schedule 21.01.2009

Локальные временные таблицы являются поточно-ориентированными, поскольку они существуют только в текущем контексте. Не путайте контекст с текущим подключением (из MSDN: "A локальная временная таблица, созданная в хранимой процедуре, автоматически удаляется по завершении хранимой процедуры »), одно и то же соединение может безопасно вызывать два или более раз хранимую процедуру, которая создает локальную временную таблицу (например, #TMP).

Вы можете проверить это поведение, выполнив следующую хранимую процедуру из двух подключений. Этот SP будет ждать 30 секунд, поэтому мы можем быть уверены, что два потока будут запускать свои собственные версии таблицы #TMP одновременно:

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;
person Gerardo Lima    schedule 08.05.2012
comment
Приведенные вами примеры, похоже, не подтверждают вашу точку зрения: локальные временные таблицы only exist within the current context. Please don't confuse context with current connection. Если он работает так, как вы описали, процедуру следует без проблем вызывать повторно в одном сеансе, если соответствующая локальная временная таблица создается внутри контекста процедуры, а не вне этой процедуры? - person Ben; 09.07.2018
comment
Спасибо, раздел временных таблиц статьи, которую вы связали, объяснил мне все: docs.microsoft.com/en-us/sql/t-sql/statements/ - person Ben; 09.07.2018

Короткий ответ:

Изоляция временных таблиц гарантируется для каждого запроса, и не о чем беспокоиться ни о потоках, ни блокировках, ни о параллельном доступе.

Я не уверен, почему ответы здесь говорят о значении «соединений» и потоков, поскольку это концепции программирования, тогда как изоляция запросов обрабатывается на уровне базы данных.

Локальные временные объекты разделяются сеансом на сервере SQL. Если у вас есть два запроса, выполняемых одновременно, это два совершенно разных сеанса, которые не будут мешать друг другу. Логин не имеет значения, поэтому, например, если вы используете одну строку подключения с помощью ADO.NET (это означает, что несколько одновременных запросов будут использовать один и тот же логин SQL-сервера), все ваши запросы будут по-прежнему выполняться отдельно сеансы. Пул соединений также не имеет значения. Локальные временные объекты (таблицы и хранимые процедуры) полностью защищены от просмотра другими сеансами.

Чтобы прояснить, как это работает; в то время как ваш код имеет одно общее имя для локальных временных объектов, SQL Server добавляет уникальную строку к каждому объекту для каждого сеанса, чтобы сохранить их отдельно. Вы можете убедиться в этом, запустив в SSMS следующее:

CREATE TABLE #T (Col1 INT)

SELECT * FROM tempdb.sys.tables WHERE [name] LIKE N'#T%';

Для имени вы увидите что-то вроде следующего:

T_______________00000000001F

Затем, не закрывая вкладку запроса, откройте новую вкладку запроса, вставьте тот же запрос и запустите его снова. Теперь вы должны увидеть что-то вроде следующего:

T_______________00000000001F

T_______________000000000020

Таким образом, каждый раз, когда ваш код ссылается на #T, SQL Server преобразует его в собственное имя в зависимости от сеанса. Разделение происходит автоматически.

person Chris Halcrow    schedule 18.07.2017

Временные таблицы привязаны к сеансу, поэтому, если разные пользователи запускают вашу процедуру одновременно, конфликта нет ...

person Jason Punyon    schedule 21.01.2009

Временные таблицы создаются только в контексте запроса или процесса, который их создает. Каждый новый запрос получает контекст в базе данных, свободный от временных таблиц других запросов. Таким образом, конфликт имен не является проблемой.

person Yes - that Jake.    schedule 21.01.2009
comment
Я думаю, это можно сказать по каждой процедуре, но не по каждому запросу. Или вы не сможете позже запросить ту же временную таблицу. разве вы имеете в виду запрос window? - person Ben; 09.07.2018

Если вы посмотрите в базу данных temps, вы увидите там временные таблицы с именами, сгенерированными системой. Так что, кроме обычных тупиков, все должно быть в порядке.

person Otávio Décio    schedule 21.01.2009

если вы не используете два знака решетки ## temp, временная таблица будет локальной и существует только для этого локального подключения к пользователю.

person SQLMenace    schedule 21.01.2009

Сначала убедитесь, что вы используете настоящие временные таблицы, они начинаются с # или ##? Если вы создаете реальные таблицы на лету, а затем повторно их отбрасываете и воссоздаете, у вас действительно будут проблемы с одновременными пользователями. Если вы создаете глобальные временные таблицы (начинающиеся с ##), у вас также могут быть проблемы. Если вам не нужны проблемы с параллелизмом, используйте локальные временные таблицы (они начинаются с символа #). Также рекомендуется явно закрывать их в конце процедуры (или когда они больше не нужны процессу, если вы говорите о длительных многошаговых процессах) и проверять наличие (и отбрасывать, если это так) перед созданием .

person HLGEM    schedule 21.01.2009