文章
· 九月 23 阅读大约需 5 分钟

IRIS的列存储介绍

InterSystems IRIS 数据平台作为关系数据库使用时,传统上以行为单位存储数据。现在,由于底层数据结构的灵活性,您也可以按列存储数据。虽然每种选择都有其优点,但在列中存储数据(称为列式存储)可以在数据分析的业务中显著提高各种用例的性能。列存储自2022.2 版的IRIS起做实验功能引入, 2023.1 起正式支持,到目前已经迭代了几个版本。

假设一家公司使用基于行的存储来保存收到的所有订单数据,跟踪订单 ID、订单日期、客户、优先级、状态和总金额等数据,使用行存储可以被示意为下面的图形:

row_storage

每一行数据在逻辑上对应一个订单,单行中的所有数据在物理上存储在一起。

这种模式便于快速添加或更新订单。订单可以一次添加一个,数据库的每次写入正好对应一行。当发生了订单的事务,除了要更改的行之外,无需访问或更新表中的任何数据。

让我们考虑另外的情况:假设公司想找到每个月的平均销售收入。为此,您只需要两列的信息: 订单日期和总金额。但是,如果使用基于行的存储,则必须检索每个订单的所有数据才能获得此信息。即使在 OrderDate 列上使用了索引,仍需要读取日期范围内每个订单的完整行,才能获得总金额。如果订单数量较多,这样做的效率会非常低。

这就是列式存储的作用所在。数据不是按行存储在一起,而是按列存储在一起。从逻辑上讲,表和数据之间的关联保持不变。改变的只是物理存储方法。

如下图所示数据是按一列列,也就是一个字段一个字段存储的。

columnar_storage

让我们看看使用列式存储时,如何获取给定月份的平均收入。您只需读取两列数据: 订单日期和总金额。您可以对 OrderDate 列进行过滤,选择某个月份的订单,然后使用快速向量化处理从 TotalAmount 列计算平均值。

这样存储数据有几个好处。首先,可以更快地运行分析查询。列式存储大大减少了普通查询必须检索的无关数据量。我们不需要读取每个订单的所有数据,而只需要读取订单日期和总金额列。由于我们是按日期进行筛选,因此读取的所有数据都是相关的。

利用现代 CPU 上的低级指令,还可以对数据块而不是单个值进行操作。这种效率的提高可以大大改善您的分析能力。

列式存储的另一个好处是,列中的所有元素都具有相同的数据类型,从而实现了高效压缩。例如,Status 列中的所有条目都只由几个可能的字符串组成。在这种情况下,列可以维护一个不同状态的字典,并只存储指向字典条目的指针,而不是完整的字符串。这样做可以避免存储重复值,从而大大提高每列的编码效率。这也使得列数据的读取更加高效。.

在数据仓库等典型的分析性工作负载中,列式存储的优势非常明显。不过,在许多使用案例中,纯粹的列存储模型并不是最佳方法。例如,在运行事务检索或更新单行时,列式存储就不太理想。因为您需要访问存储该行数据的所有列,最终会调用比所需更多的数据。

在 InterSystems IRIS 中,数据存储在Global中,因此可以同时使用基于行的存储和列式存储。利用这种灵活的方法,你可以选择按列存储某些需要快速查询的数据,同时按行存储其余数据,这样你仍然可以运行快速事务来检索或更新单行。

状态和优先级等数据可能会更新几次,因此这些事务将受益于行存储。您可以将 TotalAmount 存储在列存储中,以便于访问和分析,同时将表的其他部分存储在行中,如下图所示:

列存储的实现

列存储的实现非常简单:只需在表定义的末尾添加一个存储类型子句 WITH STORAGETYPE = COLUMNAR 即可。查询数据的方式不会发生任何变化,因此只要使用列式存储定义了表,就可以开始运行快速分析查询。

下面是列存储表的定义例子:

CREATE TABLE Sample.TransactionHistory (
  AccountNumber INTEGER,
  TransactionDate DATE,
  Description VARCHAR(100),
  Amount NUMERIC(10,2),
  Type VARCHAR(10))
WITH STORAGETYPE = COLUMNAR

而下面的定义中表的存储类型为行存储(默认存储方式), 而Amount字段定义为列式存储

CREATE TABLE Sample.BankTransaction (
  AccountNumber INTEGER,
  TransactionDate DATE,
  Description VARCHAR(100),
  Amount NUMERIC(10,2) WITH STORAGETYPE = COLUMNAR,
  Type VARCHAR(10))

除了上面的定义外,IRIS还运行用户创建基于列式存储的索引。对于已有的行存储表的数据中的某列创建列式存储的索引,可以达到将此列定义为列存储的相同效果。

CREATE TABLE Sample.BankTransaction (
  AccountNumber INTEGER,
  TransactionDate DATE,
  Description VARCHAR(100),
  Amount NUMERIC(10,2),
  Type VARCHAR(10))

CREATE COLUMNAR INDEX AmountIndex
ON Sample.BankTransaction(Amount)

行列存储的选择

对于利用InterSystems SQL或Objects的应用程序,尤其是事务处理类应用程序,行存储布局是正确的选择。而如果应用程序采用的是分析类操作,如果分析性查询的性能不令人满意,在保持行存储布局的情况下,应该对于用于聚合的数字字段,或范围条件的字段,添加列式索引。最后, OLAP数据平台, 数据仓库,使用列式存储,或者行列混存布局,可以大幅提高查询效率。

如果您想了解更多, 请阅读在线文档-选择SQL表的存储类型

讨论 (0)1
登录或注册以继续