размер табличной переменной sql без использования DATALENGTH - PullRequest
3 голосов
/ 19 декабря 2011

Как определить пространство, используемое табличной переменной, без использования DATALENGTH во всех столбцах?

Например:

DECLARE @T TABLE
(
a bigint,
b bigint,
c int,
d varchar(max)
)

insert into @T select 1,2,3, 'abc123'

exec sp_spaceused @T

Попытка определить, сколько памяти переменной таблицыпотребляет при запуске хранимой процедуры.

Я знаю, что в этом примере я могу пойти:

SELECT DATALENGTH(a) + DATALENGTH(b) + DATALENGTH(c) + DATALENGTH(d)

Но есть ли другой способ, кроме выполнения DATALENGTH для всех столбцов таблицы?

1 Ответ

1 голос
/ 19 декабря 2011

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

Основным препятствием является то, что табличной переменной будет присвоено автоматически сгенерированное имя, например #3D7E1B63, и я не уверен, существует ли прямой способ определения ее object_id.

В приведенном ниже коде используется недокументированная функция %%physloc%% (требуется SQL Server 2008+) для определения страницы данных, принадлежащей переменной таблицы, а затем DBCC PAGE для получения связанной object_id. Затем он выполняет код, скопированный непосредственно из процедуры sp_spaceused, для возврата результатов.

DECLARE @T TABLE
(
a bigint,
b bigint,
c int,
d varchar(max)
)

insert into @T select 1,2,3, 'abc123'
DECLARE @DynSQL nvarchar(100)

SELECT TOP (1) @DynSQL = 'DBCC PAGE(2,' + 
                       CAST(file_id AS VARCHAR) + ',' + 
                       CAST(page_id AS VARCHAR) + ',1) WITH TABLERESULTS' 
FROM @T
CROSS APPLY sys.fn_PhysLocCracker(%%physloc%%)


DECLARE @DBCCPage TABLE (
    [ParentObject] [varchar](100) NULL,
    [Object] [varchar](100) NULL,
    [Field] [varchar](100) NULL,
    [VALUE] [varchar](100) NULL
) 
INSERT INTO @DBCCPage
EXEC (@DynSQL)

DECLARE @id int

SELECT @id = VALUE
FROM @DBCCPage 
WHERE Field = 'Metadata: ObjectId'



EXEC sp_executesql N'
USE tempdb

declare @type character(2) -- The object type.  
  ,@pages bigint   -- Working variable for size calc.  
  ,@dbname sysname  
  ,@dbsize bigint  
  ,@logsize bigint  
  ,@reservedpages  bigint  
  ,@usedpages  bigint  
  ,@rowCount bigint  
/*  
 ** Now calculate the summary data.   
 *  Note that LOB Data and Row-overflow Data are counted as Data Pages.  
 */  
 SELECT   
  @reservedpages = SUM (reserved_page_count),  
  @usedpages = SUM (used_page_count),  
  @pages = SUM (  
   CASE  
    WHEN (index_id < 2) THEN (in_row_data_page_count + lob_used_page_count + row_overflow_used_page_count)  
    ELSE lob_used_page_count + row_overflow_used_page_count  
   END  
   ),  
  @rowCount = SUM (  
   CASE  
    WHEN (index_id < 2) THEN row_count  
    ELSE 0  
   END  
   )  
 FROM sys.dm_db_partition_stats  
 WHERE object_id = @id;  

 /*  
 ** Check if table has XML Indexes or Fulltext Indexes which use internal tables tied to this table  
 */  
 IF (SELECT count(*) FROM sys.internal_tables WHERE parent_id = @id AND internal_type IN (202,204,211,212,213,214,215,216)) > 0   
 BEGIN  
  /*  
  **  Now calculate the summary data. Row counts in these internal tables don''t   
  **  contribute towards row count of original table.  
  */  
  SELECT   
   @reservedpages = @reservedpages + sum(reserved_page_count),  
   @usedpages = @usedpages + sum(used_page_count)  
  FROM sys.dm_db_partition_stats p, sys.internal_tables it  
  WHERE it.parent_id = @id AND it.internal_type IN (202,204,211,212,213,214,215,216) AND p.object_id = it.object_id;  
 END  

 SELECT   
  name = OBJECT_NAME (@id),  
  rows = convert (char(11), @rowCount),  
  reserved = LTRIM (STR (@reservedpages * 8, 15, 0) + '' KB''),  
  data = LTRIM (STR (@pages * 8, 15, 0) + '' KB''),  
  index_size = LTRIM (STR ((CASE WHEN @usedpages > @pages THEN (@usedpages - @pages) ELSE 0 END) * 8, 15, 0) + '' KB''),  
  unused = LTRIM (STR ((CASE WHEN @reservedpages > @usedpages THEN (@reservedpages - @usedpages) ELSE 0 END) * 8, 15, 0) + '' KB'')  


', N'@id int',@id=@id

Возвращает

name                           rows        reserved           data               index_size         unused
------------------------------ ----------- ------------------ ------------------ ------------------ ------------------
#451F3D2B                      1           16 KB              8 KB               8 KB               0 KB
...