【问题标题】:Poor performance on Amazon Redshift queries based on VARCHAR size基于 VARCHAR 大小的 Amazon Redshift 查询性能不佳
【发布时间】:2014-08-10 06:53:44
【问题描述】:

我正在构建一个 Amazon Redshift 数据仓库,并且遇到了基于 VARCHAR 列的定义大小的意外性能影响。详情如下。我的三个专栏来自 pg_table_def:

 schemaname | tablename |     column      |            type             | encoding  | distkey | sortkey | notnull 
------------+-----------+-----------------+-----------------------------+-----------+---------+---------+---------
 public     | logs      | log_timestamp   | timestamp without time zone | delta32k  | f       |       1 | t
 public     | logs      | event           | character varying(256)      | lzo       | f       |       0 | f
 public     | logs      | message         | character varying(65535)    | lzo       | f       |       0 | f

我最近运行了 Vacuum 和 Analyze,我在数据库中有大约 1 亿行,我看到的性能非常不同,具体取决于我包含的列。

查询 1: 例如,以下查询大约需要 3 秒:

select log_timestamp from logs order by log_timestamp desc limit 5;

查询 2: 要求更多数据的类似查询在 8 秒内运行:

select log_timestamp, event from logs order by log_timestamp desc limit 5;

查询 3: 但是,这个查询与前面的非常相似,需要 8 分钟才能运行!

select log_timestamp, message from logs order by log_timestamp desc limit 5;

查询 4: 最后,这个查询与慢查询相同,但有明确的范围限制,非常快(~3s):

select log_timestamp, message from logs where log_timestamp > '2014-06-18' order by log_timestamp desc limit 5;

message 列被定义为能够容纳更大的消息,但实际上它并没有容纳太多数据:消息字段的平均长度为 16 个字符(std_dev 10)。事件字段的平均长度为 5 个字符(std_dev 2)。我真正能看到的唯一区别是 VARCHAR 字段的最大长度,但我认为这不会对简单查询返回的时间产生一个数量级的影响!

任何见解将不胜感激。虽然这不是这个工具的典型用例(我们将汇总远远超过我们将检查单个日志),但我想了解我的表格设计的任何微妙或不那么微妙的影响。

谢谢!

戴夫

【问题讨论】:

  • 您是否尝试过多次运行查询? Redshift 似乎将列缓存在内存中,因此对列的第一次引用可能比后续引用要慢。
  • 是的,我重新运行了这些查询,引用的性能时间似乎可靠且可重复。

标签: sql amazon-redshift


【解决方案1】:

Redshift 是一个“真正的列式”数据库,仅读取查询中指定的列。因此,当您指定 2 个小列时,只需读取这 2 个列。但是,当您添加到第 3 大列时,Redshift 必须做的工作会急剧增加。

这与将整行存储在一起的“行存储”数据库(SQL Server、MySQL、Postgres 等)非常不同。在行存储中,添加/删除查询列对响应时间没有太大影响,因为无论如何数据库都必须读取整行。

最后,您的最后一个查询非常快的原因是您告诉 Redshift 它可以跳过大部分数据。 Redshift 将您的每一列存储在“块”中,这些块根据您指定的排序键进行排序。 Redshift 会记录每个块的最小值/最大值,并且可以跳过任何不能包含要返回的数据的块。

limit 子句不会减少必须完成的工作,因为您告诉 Redshift 它必须首先按 log_timestamp 降序排列 all问题是您的 ORDER BY ... DESC 必须在整个潜在结果集上执行,然后才能返回或丢弃任何数据。列小时快,列大时慢。

【讨论】:

  • 这如何回答为什么查询 2 和 3 具有如此不同的性能的问题?两者都只触及 2 列。
  • 查询 2 包含一个 VARCHAR(256),我怀疑它的基数低且压缩程度高。查询 3 包括一个 VARCHAR(MAX),我怀疑它在很大程度上是每行唯一的,并且占用 100-1000 倍的磁盘空间。问题是您的 ORDER BY ... DESC 必须在整个潜在结果集上执行,然后才能返回或丢弃任何数据。列小时速度快,列大时速度慢。
  • 我认为基数和压缩实际上是这里的关键。每行不是唯一的,但有许多唯一条目,以及几乎 2 个数量级的不同条目。谢谢!
  • 关于查询 2,这里是来自亚马逊文档的有用注释:“为了方便,不要习惯使用最大列大小。相反,请考虑您可能存储的最大值例如,一个 VARCHAR 列,并相应地调整列的大小。因为 Amazon Redshift 非常有效地压缩列数据,所以创建比所需大得多的列对数据表大小的影响最小。但是,在处理复杂查询期间,中间查询结果可能需要存储在未压缩的临时表中”。
【解决方案2】:

出于好奇,这需要多长时间?

select log_timestamp, message
from logs l join
     (select min(log_timestamp) as log_timestamp
      from (select log_timestamp
            from logs
            order by log_timestamp desc
            limit 5
           ) lt
     ) lt
     on l.log_timestamp >= lt.log_timestamp;

【讨论】:

  • 该查询不太可运行,但我认为大致是您查询的意图的以下查询在 3 秒内运行:select log_timestamp, message from logs where log_timestamp > '2014-06-18' order by log_timestamp desc limit 5;
猜你喜欢
  • 1970-01-01
  • 2013-10-24
  • 2014-12-10
  • 2017-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-20
相关资源
最近更新 更多