使用 TinyInt 还是 Bit 对 SQL Server 有影响吗?大小和查询性能
Posted
技术标签:
【中文标题】使用 TinyInt 还是 Bit 对 SQL Server 有影响吗?大小和查询性能【英文标题】:Does it make a difference in SQL Server whether to use a TinyInt or Bit? Both in size and query performance 【发布时间】:2018-04-05 11:22:08 【问题描述】:我有一个表,它有 124,387,133 行,每行有 59 列,在这 59 列中,有 18 列是 TinyInt 数据类型,所有行值都是 0 或 1。一些 TinyInt 列用于索引,一些不是。
如果我将 tinyint 更改为一点,我的问题是否会对查询性能和表大小产生影响?
【问题讨论】:
【参考方案1】:每条记录将节省大约 15 个字节,总共 1.8 GB。
您还有 41 个字段。如果我假设这些是 4 字节整数,那么您当前的总大小约为 22 GB。总体节省不到 10% - 如果其他字段更大,可能会少得多。
这确实意味着全表扫描会快 10% 左右,因此您可以了解性能提升和幅度。
我相信位字段需要一两个额外的操作来屏蔽位和读取 - 这些天以纳秒为单位测量的微不足道的开销 - 但要记住一些事情。
较小的页面大小的好处是在一个页面上可以容纳更多的记录,因此该表在内存中占用的空间更少(假设一次全部读入)和更少的磁盘空间。较小的数据并不总是意味着提高查询性能。这里有两个警告:
-
如果您正在读取单个记录,则需要将整个页面读入缓存。确实,使用暖缓存的情况不太可能发生缓存未命中,但从冷缓存中读取单个记录的总体情况是相同的。
如果您正在读取整个表,SQL Server 实际上会读取块中的页面并实现一些预读(也称为预读或预取)。如果您正在执行复杂的处理,您甚至可能不会注意到额外的 I/O 时间,因为 I/O 操作可以与计算并行运行。
对于删除和更新等其他操作,有时会在页面级别进行锁定。在这些情况下,稀疏页面可以带来更好的性能。
【讨论】:
【参考方案2】:理论上是的,实际上差异会很微妙,18 位字段被字节打包并四舍五入,所以它变成了 3 个字节。根据可空性/任何可空性更改,存储成本将再次发生变化。两种类型都保持在行的固定宽度部分内。因此,对于这些字段,您将从 18 个字节减少到 3 个字节 - 根据行的整体大小与页面大小,您可能会在页面上挤压额外的行。 (行/页面密度是性能提升主要体现的地方,如果你想获得的话)
这似乎是一种过早的微优化,但是,如果您的性能不佳,请进行调查并收集支持任何更改的证据。应该仔细考虑对现有系统进行类型更改,如果您需要更改代码,这会提示进行完整的回归测试等,更改的成本会急剧上升 - 最终结果很少。 (大型数据集的生产更改也不会很快,因此您可以在成本中考虑一些停机时间来进行更改)
【讨论】:
可空性不影响存储。 SQL Server 为所有字段存储一个可以为空的位数组,而不考虑关于可空性的元数据信息。 你是对的,只要至少 1 个字段可以为空,它就会存储位图。【参考方案3】:实际上,使用正确的数据类型是件好事。以下是我在使用位数据类型时可以看到的好处
1.缓冲池节省,页面从存储中读入内存,可以分配更少的内存
2.索引键的大小会更小,因此一页可以容纳更多的行,并且可以减少遍历
您还可以看到节省存储空间的直接好处
【讨论】:
无论如何,一个页面将占用内存中的相同空间,它是一个 8k 页面 - 我认为你的意思是由于每页的行密度更高,可能会更少的页面被读入内存。当然,仅当字段在索引内时,索引大小才适用。【参考方案4】:如果您不知道,与 TinyInt(1 位对 8 位)相比,bit 使用更少的空间来存储信息。所以你会节省空间改为位,理论上性能应该更好。通常很难注意到这样的性能改进,但是根据您拥有的数据量,它实际上可能会有所作为,我会在备份副本中对其进行测试。
【讨论】:
这不一定是真的。默认情况下,tinyint 和 a bit 的大小完全相同:一个字节(8 位)。你不能在内存中存储一个比特;它不能被唯一地解决。但是 SQL Server 会对多个相邻的位列进行位域压缩,因此 1-8 个相邻的位列将被压缩为 1 个字节。以上是关于使用 TinyInt 还是 Bit 对 SQL Server 有影响吗?大小和查询性能的主要内容,如果未能解决你的问题,请参考以下文章
为啥 MySQL 将布尔值解释为 TINYINT(1) 而不是 BIT(1)?
tinyint(3) 在 (SQLite) SQL 中是啥意思?