【问题标题】:Can anybody explain SQL Server 2005 table size谁能解释 SQL Server 2005 表大小
【发布时间】:2010-01-03 14:17:15
【问题描述】:

我正在使用 SQL Server 2005 并且只有一个表:

int Code1,
int Code2, 
real Val1,
real Val2,
real Val3,

Code1 & Code2 作为主键,是聚集索引的一部分(只有一个索引)。 每个参数占4个字节(每行占20个字节)。

表中有2450万条记录,填充因子为100%,索引占用2MB,页面大小为4k。

假设每个页面由尽可能多的记录填充,那么每个页面应包含 204 条记录,即 4080 字节(%99.6 页面填充)

因此,我预计该表在磁盘上占用的大小约为 500MB(20 字节 * 24.5 M 记录),但事实是该表占用了 773MB。

我尝试了缩小和重新索引,但表大小没有改变。

我不是 SQL 专家,谁能帮忙?

【问题讨论】:

    标签: sql sql-server sql-server-2005


    【解决方案1】:

    首先,SQL Server中的页面大小为8 KB,不能更改;这是您无法控制的系统设置。

    在这 8192 个字节中,作为用户,您可以使用大约 8060 个字节 - 其余的是标题和控制结构等。

    因此,在您的情况下,每行占用 20 个字节,您应该能够获得每页 403 行。这样就可以为您提供大约 60'795 个数据页,每页 8 KB = 486 MB。

    但是:出于性能原因,SQL Server 不会根据需要分配每个页面 - SQL Server 会为您的数据库预先分配给定的大小。在 SQL Server Management Studio 中创建新数据库时,您会看到默认情况下,SQL Server 分配 3 MB 的空间,当需要更多空间时会增加 1 MB。这些设置是可变的——你没有提到它们是什么。

    此外,出于性能原因,SQL Server 通常不会将未使用的数据页“返回”回操作系统。这是一项相当昂贵的操作,而且很有可能在一段时间内再次需要这些操作。索引页面也是如此 - 如果您可能在该表上有另一个索引(即使只是为了尝试)并且它使用了许多页面,默认情况下这些页面不会返回给操作系统。

    此外,根据数据插入表的方式,数据结构中可能存在一些“漏洞” - 并非所有页面都完全达到 100% 填充。为了保持 b 树的平衡,SQL Server 甚至可能选择将页面分成两部分,即使它们还没有 100% 填满。

    总而言之:是的,从理论上和数学上讲,您的数据库应该是大约 486 MB 的数据和 2 MB 的索引 - 但如果文件大小为 770+ MB,它到底有多糟糕?真的很痛吗??


    使用这个检查 DMV(动态管理视图)的 T-SQL 脚本,您可以非常深入和详细地了解您的表索引结构、索引的每个级别上使用了多少页,以及如何使用数据页上的填充因子 - 非常有用且有助于了解!

    SELECT 
        t.NAME 'Table name',
        i.NAME 'Index name',
        ips.index_type_desc,
        ips.alloc_unit_type_desc,
        ips.index_depth,
        ips.index_level,
        ips.avg_fragmentation_in_percent,
        ips.fragment_count,
        ips.avg_fragment_size_in_pages,
        ips.page_count,
        ips.avg_page_space_used_in_percent,
        ips.record_count,
        ips.ghost_record_count,
        ips.Version_ghost_record_count,
        ips.min_record_size_in_bytes,
        ips.max_record_size_in_bytes,
        ips.avg_record_size_in_bytes,
        ips.forwarded_record_count
    FROM 
        sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'DETAILED') ips
    INNER JOIN  
        sys.tables t ON ips.OBJECT_ID = t.Object_ID
    INNER JOIN  
        sys.indexes i ON ips.index_id = i.index_id AND ips.OBJECT_ID = i.object_id
    WHERE
        T.NAME = 'your-table-name-here'
    ORDER BY
        AVG_FRAGMENTATION_IN_PERCENT, fragment_count
    

    【讨论】:

      【解决方案2】:

      我将尝试估算您的表格大小,请注意,我使用 90% 来进行经验法则填充。

      Row header                   4  bytes
      Fixed data size             20  bytes (2 X 4 bytes for int + 3 x 4 bytes for real)
      Variable size columns count  2  bytes
      NULL bitmap columns count    2  bytes
      Total for one row           28  bytes
      Available page size       8060  bytes
      Page header                 96  bytes
      Rows per page (max)        284  (Available page size - Page Header) / Total for one row
      Rule of thumb page fill     90% 
      Rows per page (expected)   255 
      Number of rows               2.45E+07 
      Number of pages          96079 
      Pages per MB               128 
      Total MB                   751 
      

      【讨论】:

      • 可用页面大小为 8096,8060 仅是单行的最大值,并且页眉不在该分配范围内 - 在您的数学中您已将其扣除。 8096 数据 + 96 标头 = 8192,即 8k。
      【解决方案3】:

      您提到主键是聚集索引的一部分。不是整个聚集索引吗?

      只是一个想法,但是如果聚集索引不是唯一的(我的意思是实际上明确声明为 UNIQUEPRIMARY KEY),那么 SQL Server 需要创建一个我认为是GUID,因此占用 8 个字节。

      如果启用快照隔离,您还可能会在行中产生额外的开销。如果在打开已提交读快照时插入或更新数据,您将始终拥有该 8 字节 RID 以及 6 字节事务序列号 (XTS)。

      旁注:您为什么使用 100 的 FILLFACTOR?如果数据从不改变,那没关系,但否则会因页面拆分而降低性能。

      【讨论】:

        【解决方案4】:

        其他人已经正确提到了页面大小是8k,但是可用于数据的数量是8096,8060这个数字是存储在页面上的单行的最大长度(不使用LoB或SLoB)。 (这种差异在设计时作为架构保险被提及)。

        可以应用各种开销,从行唯一性到可空位图 - Microsoft 确实发布了有关如何计算聚簇表/或堆大小的指南。

        聚集索引:http://msdn.microsoft.com/en-us/library/ms178085(SQL.90).aspx

        堆:http://msdn.microsoft.com/en-us/library/ms189124(SQL.90).aspx

        关于收缩,也称为“邪恶”——阅读 Paul Randal 对收缩的描述,然后尽可能避免使用它:http://www.sqlskills.com/BLOGS/PAUL/post/Why-you-should-not-shrink-your-data-files.aspx

        【讨论】:

          【解决方案5】:

          FILLFACTOR 为 100% 并不意味着每个页面都被完全填充到最大容量 - 这只是意味着 SQL Server 会尝试这样做并且仅针对叶节点。

          您还需要就未来性能与空间使用情况提出非常严肃的问题。对于这么多的记录,填充因子太紧意味着每次新的插入甚至更新都会触发相当大的重新排列,并且取决于使用情况,这也可能意味着死锁升级。并不是说您可能没有充分的理由打包并担心磁盘空间,而是您需要非常认真地提出这些问题。现在购买更大的磁盘相当便宜。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2011-11-08
            • 2010-10-13
            • 1970-01-01
            • 1970-01-01
            • 2010-10-05
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多