Amazon Redshift:当找到的表 id 不匹配时,如何将 `stl_load_errors` 行与正确的表名相关联?

Posted

技术标签:

【中文标题】Amazon Redshift:当找到的表 id 不匹配时,如何将 `stl_load_errors` 行与正确的表名相关联?【英文标题】:Amazon Redshift: How to associate `stl_load_errors` row with the correct table name when the found table id doesn't match? 【发布时间】:2019-04-02 17:53:13 【问题描述】:

问题总结

我使用 COPY 查询将数据从 S3 加载到 Redshift 表 t1

99% 的时间没有错误,数据已正确加载。所以我知道加载的表名没有错误。

但是当出现错误时,根据我加载的表,我无法始终正确跟踪加载此特定表期间发生的错误,因为对于某些已加载的表,如 t1,找到了表标识符 tblstl_load_errors 中的不对应于表t1 的预期值。

我在filenametbl 上都过滤了stl_load_errors,因为同一个S3 文件可能会加载到不同的表中,因此仅过滤文件名并不是检查在某个特定期间是否有错误的安全方法复制查询。

详情

加载的表名没有出现在这个表中,相反,我们在tbl列中得到一个整数标识符1234567。我们必须加入另一个包含名称和标识符的表stv_tbl_perm,以获取名称。这个“技巧”显示在 Redshift 文档中。

对于某些表,例如t1,在使用COPY t1 ... 后我可能在stl_load_errors 中找到的错误行将在tbl 列中具有标识符1234567,该标识符与@987654338 中的任何内容都不对应@。就好像它是一个临时表的标识符一样。

然后,当我查看stv_tbl_perm for"name"='t1' 时,我确实在id 列中找到了一个标识符10111213,但它不是我在stl_load_errors 中看到的那个。

更令人困惑的是,我过滤文件和表错误的方法对于某些 Redshift 表非常有效,找到的 id 是预期的,它与 @987654346 中的正确 name 匹配@。

为什么我对某个表的 COPY 会通过看起来像是某个表的临时表,而不是其他表?

复制

我尝试尽可能简化共享过程,并设法重现我的问题,如下所示。

1.创建表,插入行使其不为空并检查它。

CREATE TABLE IF NOT EXISTS public.t1
(
    id INTEGER,
    name VARCHAR(36),
    price NUMERIC(6,2)
);
insert into t1 VALUES (1, 'paul', 10.50);
select * from t1;

2。创建带有故意类型错误的 S3 文件

我在“id”列中写了一个字符,所以在加载时会导致类型错误。

unload ('select ''a'' as "id", ''pierre'' as "name", 2.50 as "price"')   
to 's3://my-bucket/redshift-load-error-table-id/unload/t1_' 
iam_role 'arn:aws:iam::1111111111:role/my-user'
parallel off 
delimiter ','; 

确保将my-bucket1111111111my-user 替换为您自己的值。

3.使用 COPY 将此文件加载到表中

COPY t1
from 's3://my-bucket/redshift-load-error-table-id/unload/t1_000'
iam_role 'arn:aws:iam::1111111111:role/my-user'
CSV;

查询如预期失败,在表stl_load_errors 中生成一行。

4.检查stl_load_errors中新错误行中的表id

SELECT * 
FROM stl_load_errors 
where trim(filename) = 's3://my-bucket/redshift-load-error-table-id/unload/t1_000';

我们找到与文件对应的行并保留在列tbl 中找到的表标识符,比如说"tbl" = 1234567(你会得到不同的东西)。

5.在stv_tbl_perm中查找此表标识符以获取表名

select *
from stv_tbl_perm 
where id='1234567';

这不返回任何内容,找到的标识符与stv_tbl_perm 中列出的任何永久表都不对应。 就好像它是一个临时表的标识符一样。

6.查找我们加载到的表的预期标识符

select *
from stv_tbl_perm 
where name='t1';

这会返回10111213(你会得到不同的东西),这是我应该在表stl_load_errorstbl 列中得到的标识符。

如果我尝试另一个错误的 COPY,则错误表中将出现另一行,并且另一个标识符与之前的标识符不同。这也表明它可能是临时表的标识符。

后果

因此,我无法为我应用了 COPY 查询的特定表过滤 stl_load_errors

令人惊讶的是,这个过程对于我的一些表来说非常有效,我在它适用的表和不适用的表之间找不到任何区别。

我还没有在网络上找到任何关于该问题的参考。它需要很多细节,所以也很难搜索。

有什么想法吗?

【问题讨论】:

我已在 AWS 开发人员论坛 here 上发布了我的问题。 【参考方案1】:

由于 AWS 工程师最近在我发布我的问题的 AWS 开发人员论坛上的 Redshift 功能,这被确定为实际的 Redshift 问题。

@joeharris76-AWS:

好的,感谢您提请我们注意。我们已经确定了 此问题的根源,并将调查修复。当它被固定时 注意将出现在我们的定期维护公告中 论坛顶部。

这和我们介绍的自动 DISTSTYLE 功能有关 最近。对于当前为 ALL 的 DISTSTYLE AUTO 表,我们加载 将新数据放入临时表,然后检查是否添加了新行 要求将表从 ALL 转换为 EVEN。 https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_TABLE_NEW.html

DISTSTYLE 自动 |甚至 |关键 |全部 默认为自动。 … 汽车: Amazon Redshift 会根据 表数据。例如,如果指定了 AUTO 分配方式, Amazon Redshift 最初将 ALL 分配分配给一个小表, 然后在表增长时将表更改为均匀分布 较大。分布的变化发生在后台,在少数 秒。 …

有两种方法可以解决这个问题:

    在要加载的表上定义一个显式的 DISTSTYLE,即 EVEN、KEY 或 ALL。我推荐这个选项主要用于可以 使用 KEY diststyle。如果你不使用 KEY 那么 AUTO diststyle 效率最高。

    从 stl_load_errors 中检索查询 ID,从 stl_querytext 中检索查询的 SQL,然后按名称查找表 来自 pg_class、svv_table_info 或 stv_tbl_perm。

https://forums.aws.amazon.com/thread.jspa?messageID=897976

在我的小复制中指定 DISTSTYLE 确实可以解决问题,我会将相同的解决方案应用于我的生产表,因为它们似乎符合 EVEN 样式(数亿行,没有连接)。

所以在我的复制案例中,我在表创建中添加了一行:

CREATE TABLE IF NOT EXISTS public.t1
(
    id INTEGER,
    name VARCHAR(36),
    price NUMERIC(6,2)
)
DISTSTYLE EVEN;

现在stl_load_errors 中的表标识符确实对应于stv_tbl_perm 中的预期表。

我还通过查询stl_querytext 表测试了该方法,它在我的复制案例中也有效,但我发现解析字符串以查找其中的表名不是很干净也不是很有效,所以我会坚持在我目前的情况下添加DISTSTYLE EVEN

【讨论】:

请注意,如果可以,我们强烈建议使用 AUTO diststyle 或 KEY diststyle。在大多数情况下,这些样式将提供最佳性能。当您没有用于分发数据的良好密钥或明显的密钥非常倾斜时,应使用 EVEN 作为后备。【参考方案2】:

使用pg_class 代替stv_tbl_perm。您可以使用 Postgres 目录表中的 oid(数据库对象 ID)列作为连接列

select c.relname table_name, s.* 
  from stl_load_errors s, pg_class c 
 where c.oid = s.tbl
   and c.relname = '<your table name>'

更多信息

https://docs.aws.amazon.com/redshift/latest/dg/c_join_PG.html

如果这能解决您的问题,请告诉我。

【讨论】:

这将返回与 stv_tbl_perm 相同的 ID,用于相同的表名。同样,它与stl_load_errors 中的 id 不对应。 我在我的 Redshift 集群上复制了您的案例。 SQL 中的第一列将为您提供表名。 stl_load_error 仍然有 id 您的 SQL 查询将表名作为第一列返回如果stl_load_error 中找到的tbl 的值对应于pg_class 中的oid 值。而事实并非如此,对于某些表,在我所描述的行为中,这是问题的核心。看来我的复制案例对您没有任何问题,它也适用于某些表,但不适用于其他表。 知道了。对不起,我帮不上什么忙。也许你可以试试 AWS 支持 不用担心,感谢您的尝试。 :) 我将在明天尝试 AWS 论坛,以尊重不成文的规则,即您应该等待,然后再在不同的网站上重复发布寻求帮助!我会在我的问题下链接它。

以上是关于Amazon Redshift:当找到的表 id 不匹配时,如何将 `stl_load_errors` 行与正确的表名相关联?的主要内容,如果未能解决你的问题,请参考以下文章

在 Amazon Redshift 中的表之间传输数据

在 Amazon Redshift 中使用 Diststyle ALL 的表应该有多小?

Amazon Redshift VACUUM 不成功

Amazon Redshift 表块分配

仅当表存在时如何删除 Amazon Redshift 中的表

使用大表连接更新 Amazon Redshift 中的列