这张表中使用的其余空间在哪里?

时间:2010-06-07 13:40:48

标签: sql-server

我正在使用SQL Server 2005。

我有一个表,其行大小应为124个字节。它是所有的int或浮点数,没有NULL列(所以一切都是固定的宽度)。

只有一个索引,已群集。填充因子为0。

这是表格def:

create table OHLC_Bar_Trl
(
    obt_obh_id int NOT NULL REFERENCES OHLC_Bar_Hdr (obh_id),
    obt_bar_start_ms int NOT NULL,
    obt_bar_end_ms int NOT NULL,
    obt_last_price float NOT NULL,
    obt_last_ms int NOT NULL,
    obt_bid_price float NOT NULL,
    obt_bid_size int NOT NULL,
    obt_bid_ms int NOT NULL,
    obt_bid_pexch_price float NOT NULL,
    obt_ask_price float NOT NULL,
    obt_ask_size int NOT NULL,
    obt_ask_ms int NOT NULL,
    obt_ask_pexch_price float NOT NULL,
    obt_open_price float NOT NULL,
    obt_open_ms INT NOT NULL,
    obt_high_price float NOT NULL,
    obt_high_ms INT NOT NULL,
    obt_low_price float NOT NULL,
    obt_low_ms INT NOT NULL,
    obt_volume float NOT NULL,
    obt_vwap float NOT NULL
)
go

create unique clustered index idx on OHLC_Bar_Trl (obt_obh_id,obt_bar_end_ms)

插入大量数据后,sp_spaceused将返回以下内容

name            rows        reserved           data               index_size         unused
OHLC_Bar_Trl    117076054   29807664 KB        29711624 KB        92344 KB           3696 KB

显示大约(29807664 * 1024)/ 117076054 = 260字节/行的行数。

剩下的空间在哪里?

我是否需要运行一些DBCC命令来收紧这个表(我无法以正确的索引顺序插入行,所以可能只是内部碎片)?

3 个答案:

答案 0 :(得分:2)

要更新“使用空间”统计信息,请使用sp_spaceused的第二个参数@updateusage:

EXEC sp_spaceused 'OHLC_Bar_Trl', 'true'

但是,我还首先运行ALTER INDEX ALL ON OHLC_Bar_Trl WITH REBUILD来对数据进行碎片整理。

答案 1 :(得分:2)

您可以使用sys.dm_db_index_physical_stats获取有关数据在给定表中的存储方式的详细信息。这不是最明显的用法,这是我为第一次排除故障而构建的模板:

--  SQL 2005 - fragmentation & air bubbles
 SELECT
   ob.name [Table], ind.name [Index], ind.type_desc IndexType
  ,xx.partition_number      PartitionNo
  ,xx.alloc_unit_type_desc  AllocationTyp
  ,xx.index_level
  ,xx.page_count        Pages
  ,xx.page_count / 128  Pages_MB
  ,xx.avg_fragmentation_in_percent  AvgPctFrag
  ,xx.fragment_count
  ,xx.avg_fragment_size_in_pages  AvgFragSize
  ,xx.record_count      [Rows]
  ,xx.forwarded_record_count  [ForwardedRows]
  ,xx.min_record_size_in_bytes        MinRowBytes
  ,xx.avg_record_size_in_bytes        AvgRowBytes
  ,xx.max_record_size_in_bytes        MaxRowBytes
  ,case xx.page_count
     when 0 then 0.0
     else xx.record_count / xx.page_count
   end AvgRowsPerPage
  ,xx.avg_page_space_used_in_percent  AvgPctUsed
  ,xx.ghost_record_count
  ,xx.version_ghost_record_count
 from sys.dm_db_index_physical_stats
   (
     db_id('MyDatabase')
    ,object_id('MyTable')
    ,null
    ,null
    ,'Detailed'
   ) xx
  inner join sys.objects ob
   on ob.object_id = xx.object_id
  inner join sys.indexes ind
   on ind.object_id = xx.object_id
    and ind.index_id = xx.index_id

使用它来检查SQL是否认为该行的长度与您认为的一样长,或者是否在某处使用/浪费了额外的空间。

答案 2 :(得分:0)

对于您的表,是的,124字节似乎确实是正确的行大小,并且由于您的聚簇索引是唯一的,因此您不应该在唯一化器上浪费空间。那么让我们考虑一下它是如何组合在一起的:

  • 页面大小= 8 KB(8192字节)
    • 标头= 96字节
    • 可用于数据= 8096字节
  • 行大小(固定数据)= 124字节
    • 标头= 4个字节
    • 空位图= 5个字节(21列)
    • 可变数据大小= 2(对于0个可变列)
    • 总计= 135字节
  • 每页行数=(8096/137)= 59
  • 总行数= 117076054
  • 总页数= 117076054/59 = 1984440
  • 实际尺寸= 1984440 * 8 KB = 15875520 KB

(注意:计算来自Estimating the Size of a Clustered Index

因此,您可以从中看到,您可以实现的绝对最小比率(使用total data size / max row size的更简单的数学运算)大约是每行139个字节。

当然,您说在插入一堆数据后,您会立即看到这些统计信息 - 在自动递增时,群集密钥的数据(IDENTITYNEWSEQUENTIALID)列,因此可以 以真正顺序的方式插入。如果是这种情况,您可能会遭受大量页面拆分并需要对聚集索引进行碎片整理:

ALTER INDEX idx
ON OHLC_Bar_Trl
REORGANIZE -- or REBUILD

注意:我不确定此命令在SQL Server 2005上是否可用。旧语法为:

DBCC INDEXDEFRAG('MyDB', 'OHLC_Bar_Trl', indexnum)

您可能还需要缩小数据库以回收所有丢失的空间(尽管大多数人会建议不要缩小数据,除非您有充分的理由这样做。)