列存压缩,说白了就是给长流水洗澡。想象一下下面这条 SQL 语句,它要查询一个工夫跨度挺长、数据量挺大的表里的记录。结局集大约有千万行,可是只想去掉那些冗余的日期字段。 要是是一般/平平行存,那这些数据就像一条没收线的长软管。你得把每一行数据都从头到尾拿出来,中间插入点、删除点要么跳过点,才能把富余的局部挤掉。

这种老式做法,在数据量不大凑合得通,可一旦数据量炸了,查询工夫就得爆炸。列存就不一样了,它把同一列里的数据挤到了一起,就像把衣橱的门全体拉上,只露出里面穿红衣服和穿蓝衣服的局部。 这时候压缩就显得自然了。一旦数据被压缩,每一份数据都是由大量个小的“砖块”组成的。就比如,MySQL 的 InnoDB 引擎常用的是 Double Dummy,就是每行数据被切成两半。一半是标识数据块在哪个页的标记,另一半就是那一大串日期数据。压缩的时候,就只需求压缩那个年月的数据串,那两个标记字明明挺小,简直没啥变化,也不需求压缩

这就相当于只给水管里的水加压,把数据串压缩了,那两个标记的开销就低了大量,查询速度自然也就快了。 为了搞懂这个,咱得看看一个具体的场景。假设有一张 `user_activity` 表,记录用户每天的状态变化。`date` 字段存了 2 亿条记录,`status` 字段存了 2 亿条记录。

要是彻底不压缩,查一条记录得读内存里,再写磁盘,效率极低。 但在列存里,`date` 和 `status` 是分开存到不同 UDF 里的。查 `status` 的时候,系统直接定位到对应的页里,先把日期切片了,再切出单个数据块。

这时候,`status` 列的数据就被级联压缩了。我们拿个数据看看,假设一条记录在 `status` 列里的数据块是 `01, 20, 99`。在列存里,这串数字一般会变成 `0:1, 20:99`。

这就好比把一段文字里的单词脱下了衣服,直接露出里面的名字和数量,数据压缩率直接蹭蹭往上涨。 这种压缩不光是在查的时候生效,实际上在插入和删除的时候也做得挺智能。当你新建一条记录时,系统不需求读取整行数据,而是直接定位到对应的列位置。

这时候你能够直接修改列里的数据,效率极高。

要是数据量特别大,就连不需求读取页,直接在内存里做压缩就能搞定。 不过,列存也不是万能神药,它也有自己的“脾气”。

比方说,要是你的业务里 `timestamp` 字段时常频繁更新,并且更新率挺高,那列存的优势可能就不那么明显了。出于每次更新都得重新定位到那一列的位置,再压缩

要是更新频率忒高,反而比行存还慢。

这时候就需求混合存,把常用的行数据和列数据分开放。 再细说点数据本身。在列存里,数据压缩往往能带来庞大的空间节省。

比方说,要是一行数据里前 50% 是日期,后 50% 是数值,压缩算法就能把前 50% 压缩掉,后 50% 直接原样复制。对于数值列,有些算法能把整数序列直接变成二进制,压缩比极高。就算是一些难以压缩的字符串,列存的压缩效果一般也比行存好,出于它们是独立处理的,不像行存那样务必把整行读出来再填进去。 自然,也不是所有场景都适合列存

要是数据量不大,要么表结构比较特殊,行存可能更好办、更快。列存适合数据量庞大、且时常需求按列查询的场景。

比如电商系统的用户画像表,时常要查用户的性别、年龄、购买历史。用列存,查询用户年龄的时候,系统能直接跳过几百个不相关的用户数据,只管那几列,速度绝了。 最终总结,列存的核心就是“分片压缩”。它把数据切分,让每一小片数据都能独立被压缩。通过这种分层处理,不仅下降了数据读取的开销,还提升了写入和更新的效率。

只要应用场景匹配,列存确实是处理海量数据时的一把好手。