【问题标题】:Where's the rest of the space used in this table?这张表中剩余的空间在哪里?
【发布时间】:2010-06-07 13:40:47
【问题描述】:

我使用的是 SQL Server 2005。

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

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

这是表格定义:

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 命令来收紧该表(我无法以正确的索引顺序插入行,所以可能只是内部碎片)?

【问题讨论】:

  • 如果您显示实际的列和键(例如,您的聚簇索引是否在唯一的单列主键上?)
  • 添加了表定义.....

标签: sql-server


【解决方案1】:

您可以使用 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 是否认为该行与您认为的一样长,或者是否在某处使用/浪费了额外的空间。

【讨论】:

  • 好吧,我开始运行它,但我的机器几乎停了下来。我仍在运行导入工作,我会等到完成后再试一试。我假设它会读取大部分数据页(至少,鉴于启动它会刺激我的 SQL Server 活动,我是假设的)。不过看起来很有趣,给定一个较小表的输出。
  • 在加载时阅读 BOL 中的 sys.dm_db_index_physical_stats。我没有挑选出它提供的所有信息,其中可能有些内容适用于您的环境。
  • 刚刚完成了 ALTER INDEX REORGANIZE,表格的大小与我预期的差不多(即减半)。
【解决方案2】:

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

EXEC sp_spaceused 'OHLC_Bar_Trl', 'true'

不过,我也会先运行ALTER INDEX ALL ON OHLC_Bar_Trl WITH REBUILD 来整理数据。

【讨论】:

  • ALTER INDEX 是否需要足够的空间来完整复制数据?如果是这样,我想我是吐司。在这种情况下,我可能必须将数据 bcp 输出(到网络磁盘),然后再将其 bcp 输入。在过去,这通常可以实现我的目标。
【解决方案3】:

对于您的表,是的,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)

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

【讨论】:

  • 是的,这些计算看起来正确....我是否总是需要 5 字节空数组(表中没有空值)?无论哪种方式,5个字节都不会让我崩溃。我在另一个答案中问过,我也会在这里问:你知道 REORG/REBUILD 是否需要足够的空间来复制表,还是就地完成?我可能不得不将我的数据 BCP 并读回,或者更改我的插入程序以缓存结果,直到它有足够的能力按顺序写出它们,否则。我没有足够的空间来做 35Gb 表的副本,上帝只知道日志中的内容......
  • @Eric:这 5 个字节是“保留空间”——如果你真的开始添加很多可以为空的列,那么这个数字会增加。至于你的第二个问题,ALTER INDEX REORGANIZE 需要一些额外的空间,但不是整个表的大小,REBUILD 可能需要索引的完整未分段大小。但是,如果此数据尚未投入生产,那么您可以删除并重新创建索引,这相当于重建但不需要任何额外空间 AFAIK。
  • ALTER INDEX 从 SQL Server 2005 开始
猜你喜欢
  • 2014-12-19
  • 2021-08-02
  • 2020-07-11
  • 1970-01-01
  • 1970-01-01
  • 2020-08-06
  • 2011-06-17
  • 2013-02-22
  • 1970-01-01
相关资源
最近更新 更多