【问题标题】:SQL Server performance: 50 columns vs single binary/varbinarySQL Server 性能:50 列与单个二进制/varbinary
【发布时间】:2017-05-26 14:35:42
【问题描述】:

是否可以通过将 50 个 float 列替换为单个 binary(n)n 为 50 x 4)来提高 SQL Server 2008 R2(和更新版本)插入性能?

我会假设使用固定大小的binary(n) 应该会提高性能(数据量相同,处理所有列所需的工作更少,SQL 查询更短),但许多网站建议不要使用binary 列,所以我想看看使用它是否真的有问题?

另外,问题是表相当非规范化,并且通常并非所有列都填充有值,因此varbinary(n) 可以让我在许多情况下减小行大小。有时只填充一列,但平均约 10 个。

然后第三个问题是,如何更进一步,用单个 varbinary(5*50*4) 替换(比如说)5 行 x 50 float32 列?

因此,获得一些见解会很酷:

  1. 将 1 行 50 个 float 列替换为单个 binary(200)
  2. 将 1 行 50 x float 替换为单个 varbinary(204)(标志/长度信息的几个字节) - 以在未使用列时节省空间;
  3. 将 5 行 50 x float 替换为单个 varbinary(1024)(标志/长度信息的几个字节)。

在所有情况下总是一次读取整行。

(更新)

为了澄清,存储的数据是:

 Timestamp_rounded    Value_0ms  Value_20ms  Value_40ms ... Value_980ms
 2016-01-10 10:00:00    10.0       11.1        10.5     ...    10.5

我总是读取整行,主聚集键是第一列(时间戳),我永远不必通过任何其他列查询表。

标准化数据显然会有一个Timestamp/Value 对,其中Timestamp 将具有毫秒精度。但是我将不得不存储 50 行的两列,而不是 1 行 (Timestamp + BLOB)。

【问题讨论】:

  • 在一个字段中存储多个值几乎总是错误的决定。
  • 稍后你想用这个做什么?你想如何阅读/操作这个 I'm-a-multi-value-binary-something
  • 这些浮点数是一秒钟内的测量值,我总是一次存储和读取它们。因此,如果这会提高插入性能,我的应用程序可以轻松地序列化/反序列化这些列。而我只是希望能够尽快存储
  • @Lousy,如果您永远不需要在 SQL 中读取这些值嘿,让我们从数据库中创建一个简洁的报告!哦,等等.. .) 你可以存储一个二进制流。这在 SQL-Server 中没有任何意义,但您可能会赢得几毫秒。我不会这样做...
  • 我尝试使用 SqlBulkCopy,有 50 列 vs 1 varbinary 列。在我的测试中,与 50 列相比,varbinary 版本非常快。 50Cols 版本在 30 秒内成功插入了 36000 行二进制版本插入了 160 万行。你可以在这里使用我的测试代码github.com/PeterHenell/binaryBulkInsertComparison 进行尝试。话虽如此,我认为我的代码中有一些东西对 50Cols 版本的惩罚远远超过了单 col 版本,因此更好的测试代码版本将提供更准确的结果。

标签: sql-server performance blob denormalization varbinary


【解决方案1】:

这是一个的主意。拥有 4 字节的 50 列与拥有 200 字节的一列消除了为这 50 列中的任何一个优化查询的任何希望。首先,从“经典”SQL Server pov 开始:

  • 您消除了下推谓词和扫描时间过滤
  • 您消除了索引的可能性
  • 您消除了数据纯度检查(尤其是对浮点数很重要,因为并非所有位模式都能产生有效的浮点数!)
  • 您消除了基于列统计的成本优化

随着您越来越“现代”并开始考虑 SQL Server 的更新选项:

所有这些都没有考虑到您对尝试查询数据的同胞造成的痛苦。

问题在于该表相当非规范化,并且通常并非所有列都填充有值,因此 varbinary(n) 在许多情况下可以让我减小行大小。有时只填充一列,但平均约 10 个。

然后使用行压缩存储:

ALTER TABLE <your table> REBUILD PARTITION = ALL  
   WITH (DATA_COMPRESSION = ROW);

如果数据是仅追加的并且很少更新/删除并且大多数查询是分析的,那么最好使用列存储。自 SQL Server 2016 SP1 列存储 are available across every SQL Server edition.

【讨论】:

  • 谢谢,您的评论正是我所期望的(基本上是我在网上看到的)。但问题是我只会查询第一列 (Timestamp),绝不会查询任何其他列,并且总是一次读取每一行(我已经更新了我的问题)。所以我知道我消除 (基本上,我不需要的东西:索引和保留这 50 列的统计数据的可能性),但我想看看我 获得了什么 在性能方面。
  • 1.阅读rusanu.com/2014/02/24/how-to-analyse-sql-server-performance。 2. 识别您的瓶颈。 3. 解决问题。
【解决方案2】:

作为一个实验,我尝试了两种不同的方法来比较它们。

我发现经过一些调整后,二进制版本比 50 col 版本快 3 倍左右。

这个场景非常具体,我的测试只测试了一些非常具体的东西。与我的测试设置的任何偏差都会对结果产生影响。

测试是如何进行的

对于 50 col 版本,我有 50 个可以为空的浮点列,我用 float.MaxValue 填充了所有列。

对于二进制版本,我只有一列。该列的值由 50x float.MaxValue + "|" 的字符串构成,全部连接成一个长字符串。然后将该字符串转换为 byte[] 以存储在表中。

两个表都是没有索引或约束的堆。

我的测试代码可以在这里找到https://github.com/PeterHenell/binaryBulkInsertComparison

我在带有 SSD 驱动器的 6 核工作站上的 SQL Server 2014 Developer Edition 上运行了测试。

【讨论】:

  • 非常感谢,这回答了我的问题。我可能会使用更有效的编码重复测试(即可为空的 float32 必须适合 33 位,通过一些压缩可能会略低一些,而带有 ascii 字符分隔符的简单 string.Format 通常会产生超过 10 个字节的数据) .这意味着我可能可以将多行数据放入一个 blob 中,因此我预计在这种情况下会提高约 10 倍。
【解决方案3】:

我知道纯粹主义者会讨厌这种方法,但如果您的用例确实如此有限,那么单列样式当然会更快。

但是,老实说,如果它那么简单,那么您将获得更高的性能,直接使用简单的固定宽度格式写入/查询单个文件,然后任何数据库都可以提供。备份、安全等功能都可以在文件级别完成。

例如,如果您仍然需要类似 SQL 的 API,那么有一个 jdbc csv 文件驱动程序可以使您的文件看起来像一个 SQL 连接。我敢肯定,无论您使用什么编程,其他人都会存在。恐怖的喘息声!

还要注意,那里有许多数据库技术。有些针对插入性能进行了优化,比其他的要好。

听起来您有类似传感器数据的东西,而您的列实际上更像是一个矩阵,可能具有空间意义。在这种情况下,您可能希望查看为该数据格式显式编码的数据库技术。 SciDB 就是这样一种数据库。它部分是由从事 Vertica 工作的同一个人设计的,所以我认为它具有相当不错的摄取性能。

【讨论】:

  • Sqlite 是比 CSV 文件或固定宽度文件更好的选择。
  • 但原来的 50 个字段也可以在 SQL Server 中使用,并且将表移动到内存存储 IFF 是一个临时汇总统计信息(它似乎是) - 您还可以获得减少的好处在 SSD 上磨损。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多