列式存储相比传统的行存储有何优势?

121 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第18天,点击查看活动详情

若事实表中有万亿行和PB级数据,则高效存储和查询就成为难题。维度表通常小得多(数百万行),所以主要关注事实表的存储。

虽然事实表通常超过百列,但典型数仓查询一次一般只访问其中的4或5个( "SELECT *"可是很少用于分析查询的哦)。如下查询为例:它访问大量行(在2013年每次购买水果或糖果),但只需访问fact_sales表的三列:date_key, product_sk, quantity

# 案例1:分析人们是否更倾向于购买新鲜水果或糖果,这取决于一周中的哪一天
SELECT
  dim_date.weekday,
  dim_product.category,
  SUM(fact_sales.quantity) AS quantity_sold
FROM fact_sales
  JOIN dim_date ON fact_sales.date_key = dim_date.date_key
  JOIN dim_product ON fact_sales.product_sk = dim_product.product_sk
WHERE
  dim_date.year = 2013 AND
  dim_product.category IN ('Fresh fruit', 'Candy')
GROUP BY
  dim_date.weekday, dim_product.category;

如何高效执行该查询SQL?

大多数OLTP数据库中,存储都是行布局:表的一行所有值彼此相邻存储。文档数据库也类似:整个文档通常存储为一个连续的字节序列。

为处理像案例1这样的查询,可以在 fact_sales.date_key和/或fact_sales.product_sk上使用索引,告诉存储引擎在哪查找特定日期或特定产品的所有销售。但行式存储引擎仍需将所有行(每个包含超过100个属性)从磁盘加载到内存并解析它们,并过滤掉那些不符要求的属性,这就可能耗时很长。

列式存储思想简单:不要将一行的所有值存储在一起,而是将每列的所有值存储在一起。若每列存储在一个单独文件,查询只需读取和解析查询中使用的那些列,能节省大量工作:图10:列式存储关系型数据,而不是行

列存储在关系数据模型中最容易理解,但其实也适用于非关系数据。

列式存储布局依赖于一组列文件,每个文件以相同顺序保存数据行。 因此,若需重新组装整行,可从每个单独的列文件中获取第23项,并将它们放在一起形成表的第23行。