Optimize Performance and Cost

The content of this tutorial are experience from hands-on experiment based on this blog post: https://aws.amazon.com/blogs/big-data/top-10-performance-tuning-tips-for-amazon-athena/

Partition (分区) 和 Bucketing (分桶)

Partition (分区) 和 Bucketing (分桶) 是两种将数据分区的技术. 两者都是为了在分布式的查询引擎中提高性能, 减少被扫描的数据, 提高查询的速度.

Note

这里的 bucketing 指的并不是 S3 Bucket 中的 Bucket, 而是一种逻辑概念.

首先我们要明白一个概念 Cardinality (Number of element in a set). 它指的是一个字段中, 不同的值的个数. 比如你有 10 年的 1 亿条电商购买数据. year 字段可能只有 10 种可能, month 只有 12 种, day 只有 31 种. 那么这几个字段都是 Low Cardinality 的. 而对于 OrderId, 可能有千万个购买行为, 那么就有几千万个不同的 OrderId, 那么这个字段就是 高 High Cardinality 的.

Note

字段是指二维表数据中的 Column, 或者 Json 中的 Key.

Partition 常用于 Low Cardinality 的字段. 常用于年月日时间这一类查询中常用 Range ( start <= time <= end) 进行过滤的字段. 在 S3 Bucket 中的实现表现为使用不同的 S3 Key prefix. 在文件系统中表现为使用不同的文件夹. 这样使得查询时能少扫描一些数据.

Bucketing 常用于 High Cardinality 的字段. 常用于 OrderId 这一类人类不可读, 但是机器可读的 Id 类型的字段. 常用于我们指定具体的值 或者进行 Join 的查询 (OrderId = "f90a9d8fb3671f8f4a488585461b6144"). 在 S3 Bucket 中的实现表现为使用不同的 S3 Key prefix. 在文件系统中表现为使用不同的文件夹. 其原理是指定比如 256 个桶, 然后将 OrderId 进行 hash 后除以 256 取余然后放在不同的桶中. 这样在查询具体订单的相关信息时时能够快速的定位到具体的桶中, 使得只扫描很少的数据. 并且在做 Join 的时候, 所有的相关数据都会被放到桶一个桶中, 所以 JOIN 的效率会高.

在同时使用 Partition 和 Bucketing 时, S3 Key 的 pattern 长这样: s3://my-bucket/order-dataset/year=2010/month=01/day=15/001s3://my-bucket/order-dataset/year=2010/month=01/day=15/256. …

Compress and Split file

Optimize file sizes

Use Columnar data store generation

Use Limit clause with Order By

Join Large table on the Left Small table on the right

GROUP BY highest cardinality column first, low cardinality column last

Use regexp_like instead of LIKE if multiple token used

Use approx_distinct(my_column) instead of COUNT(DISTINCT my_column) if the exact number doesn’t matter

Only include the columns that you need