В чем разница между временной таблицей и табличной переменной в SQL Server?

StackOverflow https://stackoverflow.com/questions/27894

Вопрос

В SQL Server 2005 мы можем создавать временные таблицы одним из двух способов:

declare @tmp table (Col1 int, Col2 int);

или

create table #tmp (Col1 int, Col2 int);

Каковы различия между этими двумя?Я читал противоречивые мнения о том, использует ли @tmp tempdb или все происходит в памяти.

В каких сценариях один превосходит другой?

Это было полезно?

Решение

Есть несколько различий между временными таблицами (#tmp) и табличными переменными (@tmp), хотя использование tempdb не входит в их число, как указано в ссылке MSDN ниже.

Как правило, для небольших и средних объемов данных и простых сценариев использования следует использовать табличные переменные.(Это слишком широкое правило с множеством исключений — см. ниже и последующие статьи.)

Некоторые моменты, которые следует учитывать при выборе между ними:

  • Временные таблицы — это настоящие таблицы, поэтому вы можете делать такие вещи, как СОЗДАТЬ ИНДЕКСЫ и т. д.Если у вас большие объемы данных, доступ к которым по индексу будет быстрее, временные таблицы — хороший вариант.

  • Табличные переменные могут иметь индексы с использованием ограничений PRIMARY KEY или UNIQUE.(Если вам нужен неуникальный индекс, просто включите столбец первичного ключа в качестве последнего столбца в ограничении уникальности.Если у вас нет уникального столбца, вы можете использовать столбец идентификаторов.) SQL 2014 также имеет неуникальные индексы.

  • Табличные переменные не участвуют в транзакциях и SELECTs неявно с NOLOCK.Поведение транзакции может быть очень полезным: например, если вы хотите выполнить ОТКАТ в середине процедуры, тогда табличные переменные, заполненные во время этой транзакции, все равно будут заполнены!

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

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

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

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

  • И табличные переменные, и временные таблицы хранятся в базе данных tempdb.Но табличные переменные (с 2005 года) по умолчанию используют параметры сортировки текущей базы данных, а не временные таблицы, которые используют параметры сортировки по умолчанию tempdb (ссылка).Это означает, что вы должны знать о проблемах сортировки, если используете временные таблицы, а параметры сортировки вашей базы данных отличаются от параметров сортировки tempdb, что вызывает проблемы, если вы хотите сравнить данные во временной таблице с данными в вашей базе данных.

  • Глобальные временные таблицы (##tmp) — это еще один тип временных таблиц, доступный всем сеансам и пользователям.

Еще немного чтения:

Другие советы

Просто смотрю на утверждение в принятом ответе о том, что табличные переменные не участвуют в протоколировании.

Кажется неправдой, что существует какая-либо разница в количестве журналирования (по крайней мере, для insert/update/delete операции с самой таблицей, хотя у меня есть с тех пор как нашел что в этом отношении существует небольшая разница для кэшированных временных объектов в хранимых процедурах из-за дополнительных обновлений системных таблиц).

Я рассмотрел поведение журналирования как для @table_variable и #temp таблицу для следующих операций.

  1. Успешная вставка
  2. Вставка нескольких строк, где оператор откатывается из-за нарушения ограничения.
  3. Обновлять
  4. Удалить
  5. Освободить

Записи журнала транзакций были практически идентичны для всех операций.

Версия табличной переменной на самом деле имеет несколько дополнительный записи журнала, потому что запись добавляется (а затем удаляется) из sys.syssingleobjrefs базовая таблица, но в целом было записано на несколько байт меньше, поскольку внутреннее имя табличных переменных занимает на 236 байт меньше, чем для #temp столов (на 118 меньше nvarchar персонажи).

Полный сценарий для воспроизведения (лучше всего запускать на экземпляре, запущенном в однопользовательском режиме и использующем sqlcmd режим)

:setvar tablename "@T" 
:setvar tablescript "DECLARE @T TABLE"

/*
 --Uncomment this section to test a #temp table
:setvar tablename "#T" 
:setvar tablescript "CREATE TABLE #T"
*/

USE tempdb 
GO    
CHECKPOINT

DECLARE @LSN NVARCHAR(25)

SELECT @LSN = MAX([Current LSN])
FROM fn_dblog(null, null) 


EXEC(N'BEGIN TRAN StartBatch
SAVE TRAN StartBatch
COMMIT

$(tablescript)
(
[4CA996AC-C7E1-48B5-B48A-E721E7A435F0] INT PRIMARY KEY DEFAULT 0,
InRowFiller char(7000) DEFAULT ''A'',
OffRowFiller varchar(8000) DEFAULT REPLICATE(''B'',8000),
LOBFiller varchar(max) DEFAULT REPLICATE(cast(''C'' as varchar(max)),10000)
)


BEGIN TRAN InsertFirstRow
SAVE TRAN InsertFirstRow
COMMIT

INSERT INTO $(tablename)
DEFAULT VALUES

BEGIN TRAN Insert9Rows
SAVE TRAN Insert9Rows
COMMIT


INSERT INTO $(tablename) ([4CA996AC-C7E1-48B5-B48A-E721E7A435F0])
SELECT TOP 9 ROW_NUMBER() OVER (ORDER BY (SELECT 0))
FROM sys.all_columns

BEGIN TRAN InsertFailure
SAVE TRAN InsertFailure
COMMIT


/*Try and Insert 10 rows, the 10th one will cause a constraint violation*/
BEGIN TRY
INSERT INTO $(tablename) ([4CA996AC-C7E1-48B5-B48A-E721E7A435F0])
SELECT TOP (10) (10 + ROW_NUMBER() OVER (ORDER BY (SELECT 0))) % 20
FROM sys.all_columns
END TRY
BEGIN CATCH
PRINT ERROR_MESSAGE()
END CATCH

BEGIN TRAN Update10Rows
SAVE TRAN Update10Rows
COMMIT

UPDATE $(tablename)
SET InRowFiller = LOWER(InRowFiller),
    OffRowFiller  =LOWER(OffRowFiller),
    LOBFiller  =LOWER(LOBFiller)


BEGIN TRAN Delete10Rows
SAVE TRAN Delete10Rows
COMMIT

DELETE FROM  $(tablename)
BEGIN TRAN AfterDelete
SAVE TRAN AfterDelete
COMMIT

BEGIN TRAN EndBatch
SAVE TRAN EndBatch
COMMIT')


DECLARE @LSN_HEX NVARCHAR(25) = 
        CAST(CAST(CONVERT(varbinary,SUBSTRING(@LSN, 1, 8),2) AS INT) AS VARCHAR) + ':' +
        CAST(CAST(CONVERT(varbinary,SUBSTRING(@LSN, 10, 8),2) AS INT) AS VARCHAR) + ':' +
        CAST(CAST(CONVERT(varbinary,SUBSTRING(@LSN, 19, 4),2) AS INT) AS VARCHAR)        

SELECT 
    [Operation],
    [Context],
    [AllocUnitName],
    [Transaction Name],
    [Description]
FROM   fn_dblog(@LSN_HEX, null) AS D
WHERE  [Current LSN] > @LSN  

SELECT CASE
         WHEN GROUPING(Operation) = 1 THEN 'Total'
         ELSE Operation
       END AS Operation,
       Context,
       AllocUnitName,
       COALESCE(SUM([Log Record Length]), 0) AS [Size in Bytes],
       COUNT(*)                              AS Cnt
FROM   fn_dblog(@LSN_HEX, null) AS D
WHERE  [Current LSN] > @LSN  
GROUP BY GROUPING SETS((Operation, Context, AllocUnitName),())

Полученные результаты

+-----------------------+--------------------+---------------------------+---------------+------+---------------+------+------------------+
|                       |                    |                           |             @TV      |             #TV      |                  |
+-----------------------+--------------------+---------------------------+---------------+------+---------------+------+------------------+
| Operation             | Context            | AllocUnitName             | Size in Bytes | Cnt  | Size in Bytes | Cnt  | Difference Bytes |
+-----------------------+--------------------+---------------------------+---------------+------+---------------+------+------------------+
| LOP_ABORT_XACT        | LCX_NULL           |                           | 52            | 1    | 52            | 1    |                  |
| LOP_BEGIN_XACT        | LCX_NULL           |                           | 6056          | 50   | 6056          | 50   |                  |
| LOP_COMMIT_XACT       | LCX_NULL           |                           | 2548          | 49   | 2548          | 49   |                  |
| LOP_COUNT_DELTA       | LCX_CLUSTERED      | sys.sysallocunits.clust   | 624           | 3    | 624           | 3    |                  |
| LOP_COUNT_DELTA       | LCX_CLUSTERED      | sys.sysrowsets.clust      | 208           | 1    | 208           | 1    |                  |
| LOP_COUNT_DELTA       | LCX_CLUSTERED      | sys.sysrscols.clst        | 832           | 4    | 832           | 4    |                  |
| LOP_CREATE_ALLOCCHAIN | LCX_NULL           |                           | 120           | 3    | 120           | 3    |                  |
| LOP_DELETE_ROWS       | LCX_INDEX_INTERIOR | Unknown Alloc Unit        | 720           | 9    | 720           | 9    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysallocunits.clust   | 444           | 3    | 444           | 3    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysallocunits.nc      | 276           | 3    | 276           | 3    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.syscolpars.clst       | 628           | 4    | 628           | 4    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.syscolpars.nc         | 484           | 4    | 484           | 4    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysidxstats.clst      | 176           | 1    | 176           | 1    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysidxstats.nc        | 144           | 1    | 144           | 1    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysiscols.clst        | 100           | 1    | 100           | 1    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysiscols.nc1         | 88            | 1    | 88            | 1    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysobjvalues.clst     | 596           | 5    | 596           | 5    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysrowsets.clust      | 132           | 1    | 132           | 1    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysrscols.clst        | 528           | 4    | 528           | 4    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysschobjs.clst       | 1040          | 6    | 1276          | 6    | 236              |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysschobjs.nc1        | 820           | 6    | 1060          | 6    | 240              |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysschobjs.nc2        | 820           | 6    | 1060          | 6    | 240              |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysschobjs.nc3        | 480           | 6    | 480           | 6    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.syssingleobjrefs.clst | 96            | 1    |               |      | -96              |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.syssingleobjrefs.nc1  | 88            | 1    |               |      | -88              |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | Unknown Alloc Unit        | 72092         | 19   | 72092         | 19   |                  |
| LOP_DELETE_ROWS       | LCX_TEXT_MIX       | Unknown Alloc Unit        | 16348         | 37   | 16348         | 37   |                  |
| LOP_FORMAT_PAGE       | LCX_HEAP           | Unknown Alloc Unit        | 1596          | 19   | 1596          | 19   |                  |
| LOP_FORMAT_PAGE       | LCX_IAM            | Unknown Alloc Unit        | 252           | 3    | 252           | 3    |                  |
| LOP_FORMAT_PAGE       | LCX_INDEX_INTERIOR | Unknown Alloc Unit        | 84            | 1    | 84            | 1    |                  |
| LOP_FORMAT_PAGE       | LCX_TEXT_MIX       | Unknown Alloc Unit        | 4788          | 57   | 4788          | 57   |                  |
| LOP_HOBT_DDL          | LCX_NULL           |                           | 108           | 3    | 108           | 3    |                  |
| LOP_HOBT_DELTA        | LCX_NULL           |                           | 9600          | 150  | 9600          | 150  |                  |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | sys.sysallocunits.clust   | 456           | 3    | 456           | 3    |                  |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | sys.syscolpars.clst       | 644           | 4    | 644           | 4    |                  |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | sys.sysidxstats.clst      | 180           | 1    | 180           | 1    |                  |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | sys.sysiscols.clst        | 104           | 1    | 104           | 1    |                  |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | sys.sysobjvalues.clst     | 616           | 5    | 616           | 5    |                  |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | sys.sysrowsets.clust      | 136           | 1    | 136           | 1    |                  |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | sys.sysrscols.clst        | 544           | 4    | 544           | 4    |                  |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | sys.sysschobjs.clst       | 1064          | 6    | 1300          | 6    | 236              |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | sys.syssingleobjrefs.clst | 100           | 1    |               |      | -100             |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | Unknown Alloc Unit        | 135888        | 19   | 135888        | 19   |                  |
| LOP_INSERT_ROWS       | LCX_INDEX_INTERIOR | Unknown Alloc Unit        | 1596          | 19   | 1596          | 19   |                  |
| LOP_INSERT_ROWS       | LCX_INDEX_LEAF     | sys.sysallocunits.nc      | 288           | 3    | 288           | 3    |                  |
| LOP_INSERT_ROWS       | LCX_INDEX_LEAF     | sys.syscolpars.nc         | 500           | 4    | 500           | 4    |                  |
| LOP_INSERT_ROWS       | LCX_INDEX_LEAF     | sys.sysidxstats.nc        | 148           | 1    | 148           | 1    |                  |
| LOP_INSERT_ROWS       | LCX_INDEX_LEAF     | sys.sysiscols.nc1         | 92            | 1    | 92            | 1    |                  |
| LOP_INSERT_ROWS       | LCX_INDEX_LEAF     | sys.sysschobjs.nc1        | 844           | 6    | 1084          | 6    | 240              |
| LOP_INSERT_ROWS       | LCX_INDEX_LEAF     | sys.sysschobjs.nc2        | 844           | 6    | 1084          | 6    | 240              |
| LOP_INSERT_ROWS       | LCX_INDEX_LEAF     | sys.sysschobjs.nc3        | 504           | 6    | 504           | 6    |                  |
| LOP_INSERT_ROWS       | LCX_INDEX_LEAF     | sys.syssingleobjrefs.nc1  | 92            | 1    |               |      | -92              |
| LOP_INSERT_ROWS       | LCX_TEXT_MIX       | Unknown Alloc Unit        | 5112          | 71   | 5112          | 71   |                  |
| LOP_MARK_SAVEPOINT    | LCX_NULL           |                           | 508           | 8    | 508           | 8    |                  |
| LOP_MODIFY_COLUMNS    | LCX_CLUSTERED      | Unknown Alloc Unit        | 1560          | 10   | 1560          | 10   |                  |
| LOP_MODIFY_HEADER     | LCX_HEAP           | Unknown Alloc Unit        | 3780          | 45   | 3780          | 45   |                  |
| LOP_MODIFY_ROW        | LCX_CLUSTERED      | sys.syscolpars.clst       | 384           | 4    | 384           | 4    |                  |
| LOP_MODIFY_ROW        | LCX_CLUSTERED      | sys.sysidxstats.clst      | 100           | 1    | 100           | 1    |                  |
| LOP_MODIFY_ROW        | LCX_CLUSTERED      | sys.sysrowsets.clust      | 92            | 1    | 92            | 1    |                  |
| LOP_MODIFY_ROW        | LCX_CLUSTERED      | sys.sysschobjs.clst       | 1144          | 13   | 1144          | 13   |                  |
| LOP_MODIFY_ROW        | LCX_IAM            | Unknown Alloc Unit        | 4224          | 48   | 4224          | 48   |                  |
| LOP_MODIFY_ROW        | LCX_PFS            | Unknown Alloc Unit        | 13632         | 169  | 13632         | 169  |                  |
| LOP_MODIFY_ROW        | LCX_TEXT_MIX       | Unknown Alloc Unit        | 108640        | 120  | 108640        | 120  |                  |
| LOP_ROOT_CHANGE       | LCX_CLUSTERED      | sys.sysallocunits.clust   | 960           | 10   | 960           | 10   |                  |
| LOP_SET_BITS          | LCX_GAM            | Unknown Alloc Unit        | 1200          | 20   | 1200          | 20   |                  |
| LOP_SET_BITS          | LCX_IAM            | Unknown Alloc Unit        | 1080          | 18   | 1080          | 18   |                  |
| LOP_SET_BITS          | LCX_SGAM           | Unknown Alloc Unit        | 120           | 2    | 120           | 2    |                  |
| LOP_SHRINK_NOOP       | LCX_NULL           |                           |               |      | 32            | 1    | 32               |
+-----------------------+--------------------+---------------------------+---------------+------+---------------+------+------------------+
| Total                 |                    |                           | 410144        | 1095 | 411232        | 1092 | 1088             |
+-----------------------+--------------------+---------------------------+---------------+------+---------------+------+------------------+

В каких сценариях один превосходит другой?

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

@wcm - на самом деле, чтобы выбрать, табличная переменная - это не только Ram - она ​​может частично храниться на диске.

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

Хорошая справочная статья

  1. Таблица температур:Таблицу Temp легко создавать и резервировать данные.

    Табличная переменная:Но табличная переменная требует усилий, когда мы обычно создаем обычные таблицы.

  2. Таблица температур:Результат таблицы Temp может использоваться несколькими пользователями.

    Табличная переменная:Но табличную переменную может использовать только текущий пользователь.

  3. Таблица температур:Таблица Temp будет храниться в базе данных tempdb.Это создаст сетевой трафик.Когда у нас есть большие данные во временной таблице, они должны работать по всей базе данных.Проблема с производительностью будет существовать.

    Табличная переменная:Но табличная переменная будет хранить некоторые данные в физической памяти, а затем, когда размер увеличится, она будет перемещена в базу данных tempdb.

  4. Таблица температур:Таблица Temp может выполнять все операции DDL.Это позволяет создавать индексы, удалять, изменять и т. д.,

    Табличная переменная:Тогда как табличная переменная не позволит выполнять операции DDL.Но табличная переменная позволяет нам создавать только кластеризованный индекс.

  5. Таблица температур:Таблица Temp может использоваться для текущего сеанса или глобально.Чтобы многопользовательский сеанс мог использовать результаты в таблице.

    Табличная переменная:Но табличную переменную можно использовать до этой программы.(Хранимая процедура)

  6. Таблица температур:Переменная Temp не может использовать транзакции.Когда мы выполняем операции DML с временной таблицей, можно выполнить откат или зафиксировать транзакции.

    Табличная переменная:Но мы не можем сделать это для табличной переменной.

  7. Таблица температур:Функции не могут использовать переменную temp.Более того, мы не можем выполнять операции DML в функциях.

    Табличная переменная:Но функция позволяет нам использовать табличную переменную.Но используя табличную переменную, мы можем это сделать.

  8. Таблица температур:Хранимая процедура выполнит перекомпиляцию (не может использовать тот же план выполнения), когда мы используем переменную temp для каждого последующего вызова.

    Табличная переменная:Тогда как табличная переменная этого не сделает.

Для всех, кто верит в миф о том, что временные переменные находятся только в памяти.

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

Прочтите статью здесь: ТемпБД::Переменная таблицы против локальной временной таблицы

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

Цитата взята из; Внутреннее устройство профессионального SQL Server 2012 и устранение неполадок

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

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

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

Temporary Tables versus Table Variables

ТАБЛИЧНЫЕ ПЕРЕМЕННЫЕ НЕ СОЗДАЮТСЯ В ПАМЯТИ

Существует распространенное заблуждение, что переменные таблицы являются структурами в памяти и, как таковые, будут работать быстрее, чем временные таблицы.Спасибо DMV под названием Sys.DM _ DB _ SESSION _ Space _ Использование, которое показывает использование TempDB по сеансу, ты можешь доказать, что это не так.После перезапуска SQL Server, чтобы очистить DMV, запустите следующий скрипт в Confi RM, что ваш сеанс _ ID возвращает 0 для пользователя _ Objects _ Alloc _ Page _ Count:

SELECT session_id,
database_id,
user_objects_alloc_page_count
FROM sys.dm_db_session_space_usage
WHERE session_id > 50 ;

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

CREATE TABLE #TempTable ( ID INT ) ;
INSERT INTO #TempTable ( ID )
VALUES ( 1 ) ;
GO
SELECT session_id,
database_id,
user_objects_alloc_page_count
FROM sys.dm_db_session_space_usage
WHERE session_id > 50 ;

Результаты на моем сервере показывают, что таблице выделена одна страница в базе данных tempdb.Теперь запустите один и тот же сценарий, но используйте переменную таблицы на этот раз:

DECLARE @TempTable TABLE ( ID INT ) ;
INSERT INTO @TempTable ( ID )
VALUES ( 1 ) ;
GO
SELECT session_id,
database_id,
user_objects_alloc_page_count
FROM sys.dm_db_session_space_usage
WHERE session_id > 50 ;

Какой из них использовать?

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

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

Еще одно отличие:

Доступ к таблице var возможен только из операторов внутри процедуры, которая ее создает, а не из других процедур, вызываемых этой процедурой или вложенным динамическим SQL (через exec или sp_executesql).

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top