Column-Stores vs. Row-Stores: How Different Are They Really

article/2025/11/5 8:23:17

概述

从论文的标题可以看出这篇论文不是陈述一种新的技术、架构,而更偏议论文一点,它主要的目的在于搞清楚对于分析类的查询为什么Column-Store比Row-Store好那么多?好在哪里?一般认为原因是:

分析类查询往往只查询一个表里面很少的几个字段,Column-Store只需要从磁盘读取用户查询的Column,而Row-Store读取每一条记录的时候你会把所有Column的数据读出来,在IO上Column-Store比Row-Store效率高很多,因此性能更好。

而本文的目的是要告诉你Column-Store在存储格式优势只是一方面,如果没有查询引擎上其它几个优化措施的配合,性能也不会太好的,这篇论文认为Column-Store在查询引擎层有以下几种大的优化手段:

  • 块遍历(Block Iteration)
  • 压缩(Compression)
  • 延迟物化(Late Materialization)
  • Invisible Join

其中前三点是前人就已经总结过的、在现有Column-Store上实现过了的,而最后一点是本论文的创新。下面我们一一看一下这几种优化手段的细节,最后再看看它们优化效果的对比。

四大优化策略详解

块遍历

块遍历(Block Iteration)是相对于单记录遍历(per-tuple iteration)而言的,其实说白了就是一种批量化的操作。单记录遍历的问题在于对于每个条数据,我们都要从Row数据里面抽取出我们需要的column(针对Row-Store来说),然后调用相应的函数去处理,函数调用的次数跟数据的条数成是 1:1的,在大数据量的情况下这个开销非常可观。而块遍历,因为是一次性处理多条数据,函数调用次数被降下来,当然可以提高性能。

这种提高性能的方法在Row-Store里面是case-by-case实现的(不是一种共识), 而对于Column-Store来说已经形成共识,大家都是这么做的。而如果column的值是字节意义上等宽的,比如数字类型,Column-Store可以进一步提高性能,因为查询引擎要从一个Block里取出其中一个值进行处理的时候直接用数组下标就可以获取数据,进一步提升性能。而且以数组的方式对数据进行访问使得我们可以利用现代CPU的一些优化措施比如SIMD(Single Instruction Multiple Data)来实现并行化执行,进一步提高性能。

压缩

压缩这种优化的方法对于Column-Store比对Row-Store更有效,原因很简单,我个人对压缩的理解是:

对数据进行更高效的编码, 使得我们可以以更少的空间表达相同的意思。
而能够进行更高效编码的前提是这个数据肯定要有某种规律,比如有很多数据一样,或者数据的类型一样。而Column-Store正好符合这个特点,因为Column-Store是把同一个Column – 也就是相同类型的数据保存在一起,当然比Row-Store把一条记录里面不同类型的字段值保存在一起更有规律,更有规律意味着可以有更高的压缩比。

但是为什么压缩就能带来查询的高效呢?压缩首先带来的硬盘上存储空间的降低,但是硬盘又不值钱。它的真正意义在于:数据占用的硬盘空间越小,查询引擎花在IO上的时间就越少(不管是从硬盘里面把数据读入内存,还是从内存里面把数据读入CPU)。同时要记住的是数据压缩之后,要进行处理很多时候要需要解压缩(不管是Column-Store还是Row-Store), 因此压缩比不是我们追求的唯一,因为后面解压也需要花时间,因此一般会在压缩比和解压速度之间做一个权衡。

高压缩比的典型如Lempel-Ziv, Huffman, 解压快的典型如: Snappy, Lz2
前面提到解压缩,有的场景下解压缩这个步骤可以彻底避免掉,比如对于采用Run-Length编码方式进行压缩的数据,我们可以直接在数据压缩的格式上进行一些计算:

Run-Length的大概意思是这样的, 对于一个数字序列: 1 1 1 1 2 2 2, 它可以表达成 1x4, 2x3
这样不管进行 count (4 + 3), sum (1 x 4 + 2 x 3) 等等都可以不对数据进行解压直接计算,而且因为扫描的数据比未压缩的要少,从而可以进一步的提升性能。文中还提到对于Column-Store应用压缩这种优化最好的场景是当数据是经过排序的,道理很简单,因为如果没有经过排序,那么数据就没那么“有规律”,也就达不到最好的压缩比。

延迟物化

要理解延迟物化(Late Materialization), 首先解释一下什么是物化:为了能够把底层存储格式(面向Column的), 跟用户查询表达的意思(Row)对应上,在一个查询的生命周期的某个时间点,一定要把数据转换成Row的形式,这在Column-Store里面被称为物化(Materization)。
从列式存储到行式显示

理解了物化的概念之后,延迟物化就很好理解了,意思是把这个物化的时机尽量的拖延到整个查询生命周期的后期。延迟物化意味着在查询执行的前一段时间内,查询执行的模型不是关系代数,而是基于Column的(我也不知道怎么更好的表达这种“模型”,如果有知道的朋友欢迎告知)。下面看个例子, 比如下面的查询:

1
2
3
4
SELECT name
FROM person
WHERE id > 10
and age > 20

一般(Naive)的做法是从文件系统读出三列的数据,马上物化成一行行的person数据,然后应用两个过滤条件: id > 10 和 age > 20 , 过滤完了之后从数据里面抽出 name 字段,作为最后的结果,大致转换过程如下图:
Early Materialization

而延迟物化的做法则会先不拼出行式数据,直接在Column数据上分别应用两个过滤条件,从而得到两个满足过滤条件的bitmap, 然后再把两个bitmap做位与(bitwise AND)的操作得到同时满足两个条件的所有的bitmap,因为最后用户需要的只是 name 字段而已,因此下一步我们拿着这些 position 对 name 字段的数据进行过滤就得到了最终的结果。如下图:

later Materialization

发现没有?整个过程中我们压根没有进行物化操作,从而可以大大的提高效率。

总结起来延迟物化有四个方面的好处:

  • 关系代数里面的 selection 和 aggregation 都会产生一些不必要的物化操作,从一种形式的tuple, 变成另外一种形式的tuple。如果对物化进行延迟的话,可以减少物化的开销(因为要物化的字段少了),甚至直接不需要物化了。

  • 如果Column数据是以面向Column的压缩方式进行压缩的话,如果要进行物化那么就必须先解压,而这就使得我们之前提到的可以直接在压缩数据上进行查询的优势荡然无存了。

  • 操作系统Cache的利用率会更好一点,因为不会被同一个Row里面其它无关的属性污染Cache Line。

  • 块遍历 的优化手段对Column类型的数据效果更好,因为数据以Column形式保存在一起,数据是定长的可能性更大,而如果Row形式保存在一起数据是定长的可能性非常小(因为你一行数据里面只要有一个是非定长的,比如VARCHAR,那么整行数据都是非定长的)。

Invisible Join

最后本文提出了一个具有创新性的性能优化措施: Invisible Join。Invisible Join 针对的场景是数仓里面的星型模型(Star Schema), 如果用户查询符合下面的模式就可以应用Invisible Join:

利用事实表的里面的外键跟维度表的主键进行JOIN的查询的, 最后select出一些column返回给用户。
所谓的星型模型指的是一个事实表(fact table), 周围通过外键关联一堆维度表(dimension table)的这么一种模型,

Star Schema

为了介绍Invisible Join的思路,我们要先介绍一下两种传统的方案,通过对比我们才能看Invisible Join方案的优点。

传统方案一: 按Selectivity依次JOIN

传统方案一最简单,按照 Selectivity 从大到小对表进行JOIN:

Selectivity JOIN

传统方案二: 延迟物化

方案二比较有意思, 它应用了延迟物化的策略,它先不进行JOIN,而是先在维度表上对数据进行过滤,拿到对应表的 POSITION, 然后把表的主键跟事实表的外键进行JOIN,这样我们就可以拿到两类POSITION: 事实表的POSITION和维度表的POSITION, 然后我们通过这些POSITION把数据提取出来就完成了一次JOIN, 重复以上的操作我们就可以完成整个查询。

later Materialization join

Invisible Join详解

上面两种方案都各有各的缺点:

  • 传统方案一因为一开始就做了JOIN,享受不了延迟物化的各种优化。
  • 传统方案二在提取最终值的时候对很多Column的提取是乱序的操作,而乱序的提取性能是很差的(随机IO)。

下面正式介绍一下我们的主角: Invisible JOIN

Invisible JOIN其实是对传统方案二的一种优化,传统方案二的精髓在于延迟物化,但是受制于大量的值的提取还是乱序的,性能还是不是最好。Invisible JOIN把能这种乱序的值提取进一步的减少, 它的具体思路如下:

  • 把所有过滤条件应用到每个维度表上,得到符合条件的维度表的主键(同时也是事实表的外键)。
  • 遍历事实表,并且查询第一步得到的所有外键的值,得到符合条件的bitmap(s), 这里会有多个bitmap,因为维度表可能有多个。
  • 对第二步的多个bitmap做AND操作,得到最终事实表里面符合过滤条件的bitmap。
  • 根据第三步的事实表的bitmap以及第一步的符合条件的维度表的主键值,组装出最终的返回值。

如果只是这样的话Invisible JOIN可能比上面的第二种方案好不了多少,论文认为在很多时间维度表里面符合过滤条件的数据往往是连续的,连续的好处在于,它能把lookup join变成一个值的范围检查,范围检查比lookup join要快,原因很简单,范围检查只需要所算数运算就好了,不需要做lookup,因此可能大幅度的提高性能。

性能对比

从论文提供的性能对比数字来看,这几大优化策略里面延迟物化的效果最好,能够提升性能3倍以上;压缩的优化效果次之: 两倍以上;Invisible JOIN 再次之:50% 到 70%;块遍历则能性能 5% 到 50%。
compare

而如果把这些优化手段都去掉,Column-Store的性能跟一个普通的Row-Store就没什么区别了。

总结

读这篇论文最大的收获是首先知道了到底哪些因素促使Column-Store对分析类查询性能可以大幅优于Row-Store: 延迟物化、压缩、Invisible Join以及块遍历。

特别佩服这篇论文的是很多人稍微想一下就会觉得Column-Store在分析类场景下性能优于Row-Store是天经地义的: 更少的IO,但是这篇论文详细的对各种场景进行了测试、论证,同时对Row-Store应用类似的性能优化的手段再进行测试、对比,掰开了揉碎了的分析。最终告诉我们:

Column-Store的优点不止在于它的存储格式,查询引擎层的各种优化也同样关键,而由于Row-Store本身存储格式的限制,即使在Row-Store上使用这些优化,效果也不好。

转载链接

Column-Stores vs. Row-Stores 读后感


http://chatgpt.dhexx.cn/article/0BxbQMOX.shtml

相关文章

Android应用开发之( TableLayout中stretchColumns、shrinkColumns的用法)

从字面上来看&#xff0c;TableLayout也比较简单&#xff0c;关键是要对相关的属性要熟悉&#xff0c;先看一个简单的例子&#xff08;后面为效果图&#xff09;&#xff1a; <?xml version"1.0" encoding"utf-8"?> <TableLayout xmlns:android…

CollenctionList

1.Collection集合 1.1集合体系结构【记忆】 集合类的特点 提供一种存储空间可变的存储模型&#xff0c;存储的数据容量可以随时发生改变 集合类的体系图 1.2Collection集合概述和基本使用【应用】 Collection集合概述 是单例集合的顶层接口&#xff0c;它表示一组对象&#xff…

输入界面,关于stretchColumns和selectAllOnFocus的属性设置

这是整个TableLayout的代码&#xff1a; <TableLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:tools"http://schemas.android.com/tools"android:orientation"vertical"android:layout_width"fill_parent&qu…

android:stretchcolumns=0,1,2,3,stretch_stretch是什么意思

stretch是什么意思 stretch是伸展、可伸缩的意思。具体释义如下&#xff1a; stretch英 [stretʃ] 美 [strɛtʃ] 1、动词 v.伸展;延伸;持续;包括 例&#xff1a;It is better to stretch the tight muscles first 最好先伸展一下僵硬的肌肉。 2、名词 n.伸展;弹性;一片;一…

StretchBlt()函数使用

StretchBlt函数从源矩形中复制一个位图到目标矩形&#xff0c;必要时按目前目标设备设置的模式进行图像的拉伸或压缩。 说白了功能就是缩放。 函数原型如下 函数原型&#xff1a;BOOL StretchBlt(HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeig…

STL_set/multiset

STL_set/multiset 简介&#xff1a;本文主要介绍STL中的&#xff0c;set与multiset的使用&#xff0c;只需要把本文的代码自己敲完便可学会。 set容器的基本概念 注意&#xff1a;set容器没有push_back, pop_back这两种插入接口&#xff0c;只能用insert函数进行插入 如果向s…

Column-Stores vs. Row-Stores: How Different Are They Really?

Column-Stores vs. Row-Stores: How Different Are They Really? 论文阐述的就是行存与列存 两者之间到底有什么区别 Abstract 论文首先给出结论&#xff1a;列式存储&#xff08;Column Stores&#xff09;比行式存储&#xff08;Row Stores&#xff09;在性能上好过一个数…

android:stretchcolumns=0,1,2,3,android:stretchColumns用法

TableLayout是一个使用复杂的布局&#xff0c;最简单的用法就仅仅是拖拉控件做出个界面&#xff0c;但实际上&#xff0c;会经常在代码里使用TableLayout&#xff0c;例如做出表格的效果。本文主要介绍TableLayout的基本使用方法。 < ?xml version"1.0" encoding…

cannot set a row with mismatched columns

错误&#xff1a;cannot set a row with mismatched columns 错误背景原错误情况错误原因解决方法 错误背景 在希望将dataframe a 中的特定行移至dataframe b 时出错&#xff0c;记录下自己使用的方法 原错误情况 #dataframe a 已知 a{ab:[1,2,3],bb:[3,4,5],cb:[4,5,6]} a …

TableLayout中stretchColumns、shrinkColumns的用法

android:stretchColumns"1" android:shrinkColumns"1"这两个属性是TableLayout所特有的&#xff0c;也是这两个属性影响了子对象的布局。 表格布局是按照行列来组织子视图的布局。表格布局包含一系列的Tabrow对象&#xff0c;用于定义行&#xff08;也可以…

TableLayout中stretchColumns和shrinkColumns使用

<?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:orientatio…

基于JAVA的即时通信软件

一.设计任务书 1.1 设计任务 本文设计的是一个简单的即时通信软件&#xff0c;利用 Java Socket 进行点到点通信&#xff0c;其工作机制模仿即时通信软件的基本功能&#xff0c;已实现的功能有&#xff1a; 客户端登录 客户端退出 群组成员之间传输文字或图片信息 该软件分为客…

一文教你用java实现即时通讯软件的设计

即时通讯软件即所谓的聊天工具&#xff0c;其主要用途是用于文字信息的传递与文件传输。使用eclipse作为即时通讯软件的开发工具&#xff0c;使用Socket建立通讯渠道&#xff0c;多线程实现多台计算机同时进行信息的传递&#xff0c;swing技术等进行实际开发相对比较合适。通过…

即时通讯软件七大优势详解

在以前&#xff0c;即时通讯软件被认为是一种专供个人使用的通信工具&#xff0c;随着社会的发展&#xff0c;各大商家企业开始慢慢接受这种通信工具并利用其协调公司内部沟通&#xff0c;从而满足公司的业务需求。那么即时通讯软件优势有哪些&#xff1f;为你细数它的七大优势…

开发IM即时通讯容易吗?需要什么技术

即时通讯现在已经随着互联网技术的应用走进了千家万户&#xff0c;跟早些年的通信工具不同&#xff0c;现在的即时通讯技术已经涵盖了语音即时通讯、视频即时通讯、文字即时通讯等多种方式&#xff0c;而开发即时通讯也成了很多互联网企业投身这一行业后想要尝试的内容。开发即…

桌面软件开发框架大赏

本文基于海康威视桌面端技术专家刘晓伦在「RTC Dev Meetup • 杭州站丨大前端时代的业务架构和跨端实践」活动中分享内容二次整理。 以下正文&#xff1a; 今天要与大家分享 19 款桌面软件开发框架&#xff0c;我将它们分了四类&#xff0c;然后分别就每个类别做相应的介绍&a…

仿QQ即时通讯软件开发-赖国荣-专题视频课程

仿QQ即时通讯软件开发—7495人已学习 课程介绍 会使用JAVA的Swing做UI&#xff0c;学会用JAVA操作数据库&#xff0c;用Java的网络编程&#xff0c;多线程编程&#xff0c;制作一个仿QQ的即时通讯软件&#xff0c;实现在局域网或者互联网通讯 课程收益 制作仿QQ即时通讯软件…

Qt制作局域网即时通讯软件

Qt制作局域网即时通讯软件 利用Qt制作的局域网即时通信软件&#xff0c;可实现文本信息、表情包、图片、文档等的传输功能。界面风格模仿的Tim&#xff0c;所以本软件取名为Timi&#xff0c;tim的mini版本。 登录界面&#xff1a;使用之前做的登录界面&#xff0c;后续修改。原…

java实现即时通讯软件

导读:即时通讯软件即所谓的聊天工具,其主要用途是用于文字信息的传递与文件传输。使用eclipse作为即时通讯软件的开发工具,使用Socket建立通讯渠道,多线程实现多台计算机同时进行信息的传递,swing技术等进行实际开发相对比较合适。通过一些轻松的注册登录后,在局域网中即…

IM即时通讯软件系统源码安卓、苹果、PC端全开源!

demo软件园每日更新资源,请看到最后就能获取你想要的: ​ 1.《计算机系统结构&#xff1a;解析思路习题》课后答案 "本书是按照全国高等教育自学考试指导委员会制定的计算机及应用专业独立本科段“计算机系统结构自学考试大纲’’要求&#xff0c;并以其指定的自学教材内…