为什么Redshift需要进行全表扫描才能找到DIST / SORT键的最大值?

时间:2016-08-23 01:23:22

标签: sql amazon-redshift

我正在对Redshift进行简单的测试,以尝试加速将数据插入Redshift表。我今天注意到的一件事是做这样的事情

CREATE TABLE a (x int) DISTSTYLE key DISTKEY (x) SORTKEY (x);
INSERT INTO a (x) VALUES (1), (2), (3), (4);
VACUUM a; ANALYZE a;

EXPLAIN SELECT MAX(x) FROM a;

产量

QUERY PLAN
XN Aggregate  (cost=0.05..0.05 rows=1 width=4)
  ->  XN Seq Scan on a  (cost=0.00..0.04 rows=4 width=4)

我知道这只有4行,但它仍然不应该进行全表扫描以找到预先排序列的最大值。不是ANALYZE完成的工作中包含的元数据吗?

正如完整性检查一样,EXPLAIN SELECT x FROM a WHERE x > 3仅扫描2行而不是整个表格。

编辑:我在表格中插入了1,000,000多行,随机值从1到10,000。做了真空和分析。查询计划仍然说它必须扫描所有1,000,004行。

1 个答案:

答案 0 :(得分:5)

在一个微小的数据集中分析查询计划并不会对数据库如何执行查询产生任何实际的见解。

优化器具有阈值,当不同计划之间的成本差异足够小时,它会停止考虑替代计划。这个想法是,对于简单的查询,搜索"完美"执行计划,可能会超过不太理想的计划的总执行时间。

RedRift已在ParAccel DB的代码上开发。 ParAccel有数百个参数可以更改/调整,以针对不同的工作负载/情况优化数据库。

由于Redshift是一个"管理"提供,它有这些设置预设在亚马逊工程师认为最佳的水平给予"预期"工作量。

通常,Redshift和ParAccel对于单切片查询并不是那么好。这些查询无论如何都倾向于在所有切片中运行,即使它们只是在一个切片中查找数据。

在切片中执行查询后,读取的最小数据量为块。根据块大小,这可能意味着数十万行。

请记住,Redshift没有索引。所以你不会有一个简单的记录查找,它会从索引中读取一些条目,然后将激光聚焦在磁盘上的单个页面上。它将始终至少读取该表的整个块,并且它将在每个切片中执行该操作。

如何使用有意义的数据集来评估查询计划?

简短的回答是,你的桌子会有一个#34;大数字"每片的数据块数。

我的表需要每片多少个块?答案取决于几个因素:

  1. 群集中的节点数
  2. 群集中的节点类型 - 每个节点的切片数
  3. 数据类型 - 每个值需要多少字节。
  4. 中涉及的列的压缩编码类型 查询。最佳编码取决于数据人口统计
  5. 所以让我们从顶部开始。

    Redshift is an MPP Database, where processing is spread accross multiple nodes. See Redshift's architecture here.

    Each node is further sub-divided in slices, which are dedicated data partitions and corresponding hardware resources to process queries on that partition of the data.

    在Redshift中创建表并插入数据时,Redshift将为每个切片分配至少一个块。

    这是一个简单的例子:

    如果您创建了一个包含两个ds1.8xlarge节点的集群,则每个节点有16个切片,两个节点总共有32个切片。

    假设我们正在查询,WHERE子句中的列类似于" ITEM_COUNT"整数。整数消耗4个字节。

    Redshift uses a block size of 1MB.

    因此,在这种情况下,您的ITEM_COUNT列可以使用至少32个块,块大小为1MB,相当于32MB的存储空间。

    如果您有32MB的存储空间且每个条目只消耗4个字节,那么您可以拥有超过800万个条目,并且它们都可以放在一个块中。

    In this example in the Amazon Redshift documentation they load close to 40 million rows to evaluate and compare different encoding techniques. Read it here.

    但等等.....

    如果你有75%的压缩率,就会有压缩,这意味着即使是3200万条记录仍然能够适应这个单块。

    底线是什么?

    为了分析您的查询计划,您需要具有多个块的表,列。在我们的例子中,32百万行仍然是一个单独的块。

    这意味着在上面的配置中,根据所有假设,具有单个记录的表基本上很可能与具有3200万条记录的表具有相同的查询计划,因为在这两种情况下数据库只需要读取每个切片一个块。

    如果您想了解数据如何跨切片分布以及使用了多少块,您可以使用以下查询:

    每个切片有多少行:

    Select trim(name) as table_name, id, slice, sorted_rows, rows
    from stv_tbl_perm
    where name like '<<your-tablename>>'
    order by slice;
    

    如何计算多少块:

    select trim(name) as table_name, col,  b.slice, b.num_values, count(b.slice)
    from stv_tbl_perm a, stv_blocklist b
    where a.id = b.tbl
      and a.slice = b.slice
    and name like '<<your-tablename>>'
    group by 1,2,3,4
    order by col, slice;