如何让你的 Spark SQL 查询加速数十倍?
gentlesie
8年前
<p>先来回答标题所提的问题,这里的答案是列存储,下面对列存储及在列存储加速 Spark SQL 查询速度进行介绍</p> <h2><strong>列存储</strong></h2> <h3><strong>什么是列存储</strong></h3> <p>传统的数据库通常以行单位做数据存储,而列式存储(后文均以列存储简称)以列为单位做数据存储,如下:</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/af57b79358d2808b2a8fb91c63ff5b76.png"></p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/29e138a436e9820f7cde60a81c04aaea.png"></p> <h3><strong>优势</strong></h3> <p>列存储相比于行存储主要有以下几个优势:</p> <ul> <li>数据即索引,查询是可以跳过不符合条件的数据,只读取需要的数据,降低 IO 数据量(行存储没有索引查询时造成大量 IO,建立索引和物化视图代价较大)</li> <li>只读取需要的列,进一步降低 IO 数据量,加速扫描性能(行存储会扫描所有列)</li> <li>由于同一列的数据类型是一样的,可以使用高效的压缩编码来节约存储空间</li> </ul> <p>当然列存储并不是在所有场景都强于行存储,当查询要读取多个列时,行存储一次就能读取多列,而列存储需要读取多次。Spark 原始支持 parquet 和 orc 两个列存储,下文的实践使用 parquet</p> <h2><strong>使用 Parquet 加速 Spark SQL 查询</strong></h2> <p>在我的实践中,使用的 Spark 版本是 2.0.0,测试数据集包含1.18亿条数据,44G,每条数据共有17个字段,假设字段名是 f1,f2...f17。</p> <p>使用 Parquet 格式的列存储主要带来三个好处</p> <p>大大节省存储空间</p> <p>使用行存储占用 44G,将行存储转成 parquet 后仅占用 5.6G,节省了 87.2% 空间,使用 Spark 将数据转成列存储耗时4分钟左右(该值与使用资源相关)</p> <h3><strong>只读取指定行</strong></h3> <p>Sql: select count(distinct f1) from tbInRow/tbInParquet</p> <p>行存储耗时: 119.7s</p> <p>列存储耗时: 3.4s</p> <p>加速 35 倍</p> <h3><strong>跳过不符合条件数据</strong></h3> <p>Sql: select count(f1) from tbInRow/tbInParquet where f1 > 10000</p> <p>行存储耗时: 102.8s</p> <p>列存储耗时: 1.3s</p> <p>加速 78 倍</p> <p>当然,上文也提到了,列存储在查询需要读取多列时并不占优势:</p> <p>Sql: select f1, f2, f3...f17 from tbInRow/tbInParquet limit 1</p> <p>行存储耗时: 1.7s</p> <p>列存储耗时: 1.9s</p> <p>列存储带来的加速会因为不同的数据,不同的查询,不同的资源情况而不同,也许在你的实践中加速效果可能不如或比我这里例子的更好,这需要我们根据列存储的特性来善用之</p> <h2><strong>参考</strong></h2> <ul> <li><a href="/misc/goto?guid=4959641508041611916" rel="nofollow,noindex">http://www.infoq.com/cn/articles/in-depth-analysis-of-parquet-column-storage-format</a></li> <li><a href="/misc/goto?guid=4959716806851784405" rel="nofollow,noindex">http://chattool.sinaapp.com/?p=1234</a></li> </ul> <p> </p> <p>来自:http://www.jianshu.com/p/d045a14930cb</p> <p> </p>