首页 > 其他分享 >列式存储的另一面

列式存储的另一面

时间:2024-08-27 13:22:47浏览次数:13  
标签:存储 读取 列式 分段 行存 数据量 另一面 硬盘 列存

列存是常见的数据存储技术,说到列存常常就意味着高性能,现代分析型数据库基本都会把列存作为标配,
列存的基本原理是减少硬盘的读取量。一个数据表有多个列,但运算可能只会用到其中少数几列,采用列存时,用不着的列就不必读出来了,而采用行式存储时,则要把所有列都扫描一遍。当取用列只占总列数的小部分时,列存的 IO 时间优势会非常大,就会显得计算速度快了很多。
不过,列存也有另一面,并不是在任何场景下都有优势。

列存的实现远比行存复杂,因为数据表的列数可以事先确定,但行数却在不断增长。行存时按记录顺序写出,有追加时继续写即可,使用单个文件也很容易实现。列存则不行,考虑到数据有追加的情况,事先就无法确定行数,不可能把一列全部写出去再写下一列。一般会分块处理,一个数据块写入固定的 N 行数据,写满后启用下一个数据块;读取时以块为单位,块内列存,块间可以理解成是行存。这需要有个专门的管理模块用目录表记着这些不断增加的数据块及其中每个列的信息,麻烦很多。所以列存很难在单个数据文件中实现,一般只会出现在专业的数据仓库产品中。

这种分块机制在数据量不太大的时候对并行计算不友好。并行时要能把数据分段。这有两个要求:每段数据量基本相同(每线程处理能力相当),可以较灵活的分段(事先不能预测并行数)。行存可以按数据行分段,很小数据量就可以并行了。列存就只能按块分段,块内数据不能再分。但是每块的记录数(就是那个 N)不能太小,否则还是会由于硬盘的最小读取单位而造成较大的浪费,极端情况 N=1 就相当于行存,而且 N 太小也会导致总数据量很大时的目录表很大,目录管理的负担过重。所以通常这个 N 会取到 100 万或更大的数,而总块数要在数百以上才能保证灵活分段,也就是说,总数据量达到几亿条以上时,列存的并行计算才会比较顺畅。
esProc SPL 有个倍增分段算法,可以让这个 N 随着数据量增加而变大,而总块数则维持固定。这样目录表规模也是固定的,在单个文件中也能方便地实现列存,较小数据量也能灵活分段并行。

从列存的原理上看,只有当运算涉及的列较少时,列存的优势才会明显。很多用于性能测试的案例(比如作为国际标准的 TPCH)也确实是这样,容易测出列存数据库的优势。但实际场景却不全是这样,像金融业务中,上百列的表且其中大部分都要用到的情况并不罕见,这时列存的效果就会大打折扣。虽然因为列存压缩比更高,读取量仍然会比行存更小,但涉及列很多时,优势并没那么明显,毕竟列存的读取过程也要比行存复杂很多。
所以,在实际场景中发现跑不出测试案例的性能时,也不要觉得很奇怪,也不表示测试是有假。

列存还会造成硬盘的随机读取。每列是连续存储的,但不同的列就不连续了。读的列越多造成的随机程度就越重,即使单线程单任务也会这样。对于固态硬盘,这个问题不算很严重,每一列都连续且上面那个 N 够大时,读取浪费占比很小,而固态硬盘没有寻道时间。
但对于机械硬盘,因为有寻道时间的存在,这将是灾难性的。在访问列数较多时,很可能发生还不如行存的性能好的现象。并发或并行还会进一步恶化这个问题。而通过加大缓冲区来缓解又会占用大量内存。
机械硬盘要慎用列存。

列存还有个较大的问题是它的索引性能要远比行存低。我们之前讲过索引表会存储有序的键值和对应记录在原表中的位置。对于行存来说,记录位置就是一个数;但列存就不一样了,一条记录的每个列各有各的位置,原则上需要都记录下来,这样一来,索引表几乎和原表一样大,空间占用大,读取成本高,这和复制原表后排序区别并不大了。
实际上当然不会这么做了,通常用的手段还是上述的分块机制,索引中只保存记录的序号。查找时从索引中读出序号,再定位到相应的块,然后从块起始点“数”到相应序号后读出列值。这个“数”的动作会针对每个列都执行,最好情况也要读出列数个硬盘单位,运气不好整个块都要扫描一遍,而行存索引一般只要读一两个硬盘单位就够了(视记录占的空间)。列存比行存的读取量会大出几十上百倍,碰到机械硬盘更是还有要命的寻道时间。所以列存基本上无法应对高并发查找的需求。

遍历用列存,查找用行存。遍历和查找都有高性能需求的数据,甚至有必要冗余两份存储。数据平台应该允许程序员根据实际情况决定采用的存储方式,而不是一刀切地替用户选择。
嗯,esProc SPL 就可以自由选择行存还是列存,还有带值索引方案可以为遍历用列存数据提供一套查找用的行存副本。

SPL源码地址

标签:存储,读取,列式,分段,行存,数据量,另一面,硬盘,列存
From: https://blog.csdn.net/smilejingwei/article/details/141566267

相关文章

  • OceanBase-【OBCP】认证-第二章 OB 存储引擎高级技术
    第二章OB存储引擎高级技术内存管理内存数据落盘策略-合并和转储LSMTree技术简介LSMTree(TheLog-StructuredMerge-Tree)核心特点是利用顺序写来提高写性能◼将某个对象(Partition)中的数据按照“key-value”形式在磁盘上有序存储(SSTable)◼数据更新先记录在MemStor......
  • 如何使用 AWS CLI 为私有 AWS S3 存储桶中的对象创建预签名 URL
    本文档的目的是介绍使用AWSCLI为s3对象创建预签名URL的步骤。欢迎来到雲闪世界。快速事实“如果您使用预签名URL,则无需将存储桶公开,事实上,最好不要这样做。”—AWSSupport背景AmazonWebServices简单存储服务(AWSS3)是AWS的服务之一,您可以以低廉的价格......
  • 网站提示507 Insufficient Storage:服务器无法存储完成请求所需的内容怎么办
    当遇到“507InsufficientStorage”错误时,这意味着服务器无法存储完成请求所需的内容,通常是由于磁盘空间不足或资源限制。这种错误通常出现在服务器端,特别是在存储资源有限的环境中。解决方案检查服务器磁盘空间如果你是服务器管理员,检查服务器的磁盘空间。确认是否有足够......
  • 【K8s】专题十二(3):Kubernetes 存储之 PersistentVolumeClaim
    本文内容均来自个人笔记并重新梳理,如有错误欢迎指正!如果对您有帮助,烦请点赞、关注、转发、订阅专栏!专栏订阅入口Linux专栏 | Docker专栏 | Kubernetes专栏往期精彩文章【Docker】(全网首发)KylinV10下MySQL容器内存占用异常的解决方法【Docker】(全网首发)Kyli......
  • 科技宅必看 解锁极致存储新境界:QNAP TS-1655混合式NAS
     Hey科技爱好者们,今天要给大家安利一款让我爱不释手的存储神器——QNAPTS-1655桌上型大容量混合式NAS!如果你也在为海量数据的存储与管理而头疼,那么这篇文章你可不能错过!......
  • 【MySQL-23】万字总结<InnoDB引擎>——【逻辑存储结果&架构(内存结构,磁盘结构,后台线程)&事
    前言大家好吖,欢迎来到YY滴MySQL系列,热烈欢迎!本章主要内容面向接触过C++的老铁主要内容含:欢迎订阅YY滴C++专栏!更多干货持续更新!以下是传送门!YY的《C++》专栏YY的《C++11》专栏YY的《Linux》专栏YY的《数据结构》专栏YY的《C语言基础》专栏YY的《单片机》专栏YY......
  • SQLserver中的触发器和存储过程
    在SQLServer中,触发器是一种特殊的存储过程,它在指定的数据库表上发生特定的数据修改事件时自动执行。触发器可以用于执行各种任务,如数据验证、数据审计、自动更新相关表等。触发器的类型SQLServer支持以下几种类型的触发器:INSERT触发器:在向表中插入新行时触发。UPD......
  • Storage:Keeping memories in the brain(存储:把记忆保存在大脑中)
    Onceyou’veencodedinformation,younowneedtostoreit.Unfortunately,forgettingisamajorpartofhowourbrainswork.Mostofuscan’trememberwhatwehadfordinnerTuesday,threeweeksago.However,wecanallrememberourfirstkiss.一旦完成......
  • MySQL数据库的带参数的存储过程
    在MySQL数据库中,带参数的存储过程是一种接受输入参数的存储过程。通过使用参数,您可以在存储过程内部访问和处理外部传递的数据。创建带参数的存储过程:使用CREATEPROCEDURE语句可以创建带参数的存储过程。参数可以是输入参数(IN)、输出参数(OUT)或输入输出参数(INOUT)。参数可以指......
  • 为什么sql server存储过程在ssms中执行很快,但是在jdbc调用时却又很慢?
    近几年老是不定期地遇到同一个问题,sqlserver的存储过程在ssms里执行很快,但是用jdbc调用就很慢。今天仔细地研究了一下,发现问题的关键在于存储过程的执行计划。存储过程在创建完之后,通常会被程序员用一组参数调用这个存储过程,查看能否执行。然而恰恰就是在这第一次在ssms里的......