即使使用 where 子句中使用的排序键,Redshift 也会执行全表扫描

Posted

技术标签:

【中文标题】即使使用 where 子句中使用的排序键,Redshift 也会执行全表扫描【英文标题】:Redshift performing full table scan even with the sort key used in where clause 【发布时间】:2019-01-08 22:49:34 【问题描述】:

我在 redshift DC28XL 集群中有一个大约 5.27 亿行的表。

我添加了特定的 varchar 列(称为段)作为我的 dist 键和排序键。每个段大约有 4M 行。当我对一个段 select * from table where segment ='s1'; 运行带有 where 子句的简单选择时,Redshift 总是执行顺序扫描并且需要 3 分钟以上。

有人可以帮助我避免全表扫描并将性能降低到 10 秒或更短吗?

【问题讨论】:

您实际上是在检查字符串吗?通过“每个段大约有 4M 行”,您的意思是 segment 的每个不同值都有大约 4M 行,是吗?请注意,即使您的数据已排序,EXPLAIN 仍会显示顺序扫描——这只是有限的顺序扫描;对于未排序的数据,成本会有所不同。例如我进行了一项测试,以检查在使用和不使用时间戳作为排序键的样本集上过滤两个时间戳之间的执行差异,并且 EXPLAIN 显示了 7 倍的加速。已排序:cost=0.00..110954.75,未排序:cost=0.00..700127.12) 我用多个更小的间隔 BETWEEN 语句(与 OR 结合)运行了相同的测试,并看到了更大的加速,大约 40 倍。 Redshift 存储数据的方式是以块为单位的,每个块都会为 sortkey 存储一个最小值/最大值。它仍然需要查看每个块,但它会发现它正在寻找的值不在该块的范围内,所以它会跳过它,依此类推,直到找到值在这些范围内的块。所以这就是为什么它仍然是顺序扫描,即使它实际上并不是扫描每一行。 是的,你是对的。段字段是 varchar,段的每个不同值大约有 4M 行。尽管它说 dist 样式是基于键的,但该表也显示出高偏差。我跑了真空并分析。我仍然得到相同的结果。 为什么要针对 400 万行数据执行 select *?你真的想要所有这些数据吗?运行select sum(value) where segment = 's1' 可能更现实,因为它与通常针对数据仓库运行的查询类型相匹配。 【参考方案1】:

Amazon Redshift 的一个好的经验法则是:

DISTKEY 设置为JOIN 中最常用的列 将SORTKEY 设置为WHERE 中最常用的列

由于您的数据由segment 分发,并且您正在查询单个segment,因此所有活动都发生在一个切片上。因此,这不是一个非常有效的操作。

如果此数据经常在WHERE 子句中使用segment,则SORTKEY 应为segment,其他应为DISTKEY(最好在JOINs 中使用,或者,如果@ 987654333@没用,那就用DISTKEY EVEN)。

【讨论】:

【参考方案2】:

如果您将分布样式设置为均匀并将排序键保留为分段,您可能会获得更好的性能。这会将数据均匀地分布在切片中,但保持段值在块内排序在一起。通过这种方式,您将获得最大程度的并行化,并最大限度地减少需要读取的块。

【讨论】:

【参考方案3】:

我同意 Nate 的分布风格应该是均匀的。 为了性能建议不要压缩排序键,你需要使用ENCODE raw

查看 Redshift 工程师回答的这个问题。

AWS Redshift : DISTKEY / SORTKEY columns should be compressed?

您可以运行ANALYZE COMPRESSION table 来确定应该压缩哪些列

【讨论】:

感谢您的意见。我今天会尝试更改并回复您。

以上是关于即使使用 where 子句中使用的排序键,Redshift 也会执行全表扫描的主要内容,如果未能解决你的问题,请参考以下文章

Oracle:尝试使用唯一键组合的“更新”语句。卡在 where 子句中

即使插入了列,“WHERE”子句中的 SQL 未知列

请教linq中orderby子句与where子句共存时排序失效问题

如何在 WHERE 子句中使用主键连接表? [关闭]

HoneySQL 不能处理 WHERE 子句中的复合键?

即使在 VB.NET 中使用 ORDER BY 子句,Oracle DataReader 也会被排序