将排序键的顺序更改为降序

Abh*_*nav 2 amazon-web-services amazon-redshift

我们有一个 2 节点 Redshift 集群,其中有一个包含大约 100M 记录的表。我们将时间戳列标记为排序键 - 因为查询始终受到时间限制。但是,我们的用例要求结果必须按降序排序(在排序键上)。

经过一些基准测试后,我们注意到平均时间约为 10 秒。然而,当取消反向排序后,平均时间降至 1 秒以下。

是否可以将排序键的顺序反转为降序?官方文档似乎没有表明这是可能的。不过,我在创建新表时尝试将其放入:

sortkey(start_time DESC)
Run Code Online (Sandbox Code Playgroud)

没有错误,但似乎没有任何效果。

编辑:添加了查询的 EXPLAIN 语句的结果。

  • order_by ASC 的查询

      explain select * from kcdr_sr_desc where user_id=396747 and start_time > '2016-01-01' and start_time < '2016-07-01' order by start_time limit 20;
    
    Run Code Online (Sandbox Code Playgroud)

    结果:

        XN Limit  (cost=0.00..10.86 rows=20 width=300)
        ->  XN Merge  (cost=0.00..709235.56 rows=1306585 width=300)
           Merge Key: start_time
            ->  XN Network  (cost=0.00..709235.56 rows=1306585 width=300)
           Send to leader
           ->  XN Seq Scan on kcdr_sr_desc  (cost=0.00..709235.56 rows=1306585 width=300)
                 Filter: ((user_id = 396747) AND (start_time > '2016-01-01 00:00:00'::timestamp without time zone) AND (start_time < '2016-07-01 00:00:00'::timestamp without time zone))
    
    Run Code Online (Sandbox Code Playgroud)
  • 使用 order_by DESC 进行查询

     explain select * from kcdr_sr_desc where user_id=396747 and start_time > '2016-01-01' and start_time < '2016-07-01' order by start_time desc limit 20
    
    Run Code Online (Sandbox Code Playgroud)

    结果:

      XN Limit  (cost=1000000841967.42..1000000841967.47 rows=20 width=300)
      ->  XN Merge  (cost=1000000841967.42..1000000845233.88 rows=1306585 width=300)
      Merge Key: start_time
         ->  XN Network  (cost=1000000841967.42..1000000845233.88 rows=1306585 width=300)
           Send to leader
           ->  XN Sort  (cost=1000000841967.42..1000000845233.88 rows=1306585 width=300)
                 Sort Key: start_time
                 ->  XN Seq Scan on kcdr_sr_desc  (cost=0.00..709235.56 rows=1306585 width=300)
                       Filter: ((user_id = 396747) AND (start_time > '2016-01-01 00:00:00'::timestamp without time zone) AND (start_time < '2016-07-01 00:00:00'::timestamp without time zone))
    
    Run Code Online (Sandbox Code Playgroud)

Joh*_*ein 7

Amazon Redshift表SORTKEY上的 区域地图 用于通过使用区域地图来提高查询效率。它的目的不是对数据进行排序以匹配查询。

Amazon Redshift 将数据以 1MB 块的形式存储在磁盘上。每个块包含与一个表的一列相关的数据,并且该列的数据可以占用多个块。块可以被压缩,因此它们通常包含超过 1MB 的数据。

磁盘上的每个块都有一个关联的区域映射,用于标识该块中所存储列的最小值和最大值。这使得 Redshift 能够跳过不包含相关数据的块。例如,如果SORTKEY是时间戳并且查询具有WHERE将数据限制为特定日期的子句,则 Redshift 可以跳过所需日期不在该块内的任何块。

一旦 Redshift 找到包含所需数据的块,它将读取这些块来执行查询。

在查看您的EXPLAIN计划时,第二个示例显然有一个额外的SORT步骤。查询优化器似乎知道您正在对与 匹配的列进行排序SORTKEY,因此在第一个示例中会跳过排序。当数据附加到表中时,这很常见,导致更新的数据出现在列的末尾。

为您提供一些选择:

  • 如果您总是进行新的数据加载,则可以添加一个与日期相反的新列(例如,从 3000 年减去存储的日期的间隔)。使用它作为SORTKEY,数据将被反向存储。真实日期列的区域地图也将方便地进行反向排序。

  • 如果您不断加载新数据,则最新数据将附加到列的末尾,因此无论如何您都无法轻松地对数据进行反向排序。

  • 使用较小的日期范围。上面的查询将结果限制在六个月的范围内,返回 1,306,585 行。然后查询对其进行排序,并将结果限制为最近的 20 个。如果减小日期范围(例如,仅一天),则检索到的数据越少,排序将运行得更快,查询也会更快。考虑到这么多行,平均每天有 7000 多条记录,因此对于LIMIT 20.

  • 不要使用SELECT *——它会导致从磁盘读取更多块(因为每一列都存储在单独的块中)。通过仅查询实际需要的列,将减少磁盘访问并且查询运行得更快。