我正在构建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 and Analyze,我在数据库中有大约1亿行,而且根据我包含的列,我看到了非常不同的性能.
select log_timestamp from logs order by log_timestamp desc limit 5;
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;
消息列被定义为能够容纳更大的消息,但实际上它不包含太多数据:消息字段的平均长度是16个字符(std_dev 10).事件字段的平均长度是5个字符(std_dev 2).我能真正看到的唯一区别是VARCHAR字段的最大长度,但我认为这不应该对简单查询返回的时间产生一个数量级的影响!
任何见解将不胜感激.虽然这不是这个工具的典型用例(我们将聚合远远超过我们将检查单个日志),但我想了解我的表设计的任何微妙或不那么微妙的影响.
谢谢!
戴夫
解决方法
Redshift是一个“真正的柱状”数据库,只读取查询中指定的列.因此,当您指定2个小列时,只需要读取这两列.但是当你添加第3个大列时,Redshift必须做的工作会大大增加.
这与整行存储在一起的“行存储”数据库(sql Server,MysqL,Postgres等)非常不同.在行存储中添加/删除查询列在响应时间上没有太大区别,因为数据库无论如何都必须读取整行.
最后你的上次查询速度非常快的原因是因为你告诉Redshift它可以跳过很大一部分数据. Redshift将您的每一列存储在“块”中,并根据您指定的排序键对这些块进行排序. Redshift记录每个块的最小值/最大值,并可以跳过任何不能包含要返回的数据的块.
limit子句不会减少必须完成的工作,因为你告诉Redshift它必须首先按log_timestamp降序排序.问题是你的ORDER BY …在返回或丢弃任何数据之前,必须在整个潜在结果集上执行DESC.当列很小而且很快时,当它们很大时它很慢.