Redshift:在插入时自动截断 VARCHAR 值或者使用最大长度?
Redshift: Truncate VARCHAR value automatically on INSERT or maybe use max length?
执行 INSERT 时,Redshift 不允许您插入比 table 中的目标字段 longer/wider 的字符串值。观察:
CREATE TEMPORARY TABLE test (col VARCHAR(5));
-- result: 'Table test created'
INSERT INTO test VALUES('abcdefghijkl');
-- result: '[Amazon](500310) Invalid operation: value too long for type character varying(5);'
一个解决方法是转换值:
INSERT INTO test VALUES('abcdefghijkl'::VARCHAR(5));
-- result: 'INSERT INTO test successful, 1 row affected'
令人讨厌的是,现在我的所有代码都必须像这样在每个 VARCHAR 字段的每个 INSERT 上使用这些强制转换语句,否则应用程序代码将不得不在尝试构造查询之前截断字符串;无论哪种方式,这都意味着列的宽度规范必须进入应用程序代码,这很烦人。
使用 Redshift 有更好的方法吗?如果有一些选项可以让服务器截断字符串并执行(并可能发出警告)与 MySQL.
相同的方式,那就太好了
我可以做的一件事就是将这些特定字段声明为非常大的 VARCHAR,甚至可能是 65535(最大值)。
create table analytics.testShort (a varchar(3));
create table analytics.testLong (a varchar(4096));
create table analytics.testSuperLong (a varchar(65535));
insert into analytics.testShort values('abc');
insert into analytics.testLong values('abc');
insert into analytics.testSuperLong values('abc');
-- Redshift reports the size for each table is the same, 4 mb
我发现这种方法的一个缺点是如果在组中使用此列会导致性能不佳 by/join/etc:
https://discourse.looker.com/t/troubleshooting-redshift-performance-extensive-guide/326
(搜索 VARCHAR)
我想知道,如果您打算从不在 group by、join 等中使用此字段,是否没有其他危害。
在我的场景中需要注意的一些事情:是的,我真的不关心可能因截断而丢失的额外字符,不,我没有办法强制源文本的长度.我正在捕获来自外部来源的消息和 URL,它们的字符长度通常在一定范围内,但有时会有更长的字符。在我们的应用程序中,它们是否在存储中被截断并不重要。
自动截断字符串以匹配列宽的唯一方法是使用带有选项 TRUNCATECOLUMNS
的 COPY 命令
Truncates data in columns to the appropriate number of characters so
that it fits the column specification. Applies only to columns with a
VARCHAR or CHAR data type, and rows 4 MB or less in size.
否则,您将不得不使用以下两种方法之一来处理字符串的长度:
将您的值显式转换为您想要的 VARCHAR:
INSERT INTO test VALUES(CAST('abcdefghijkl' AS VARCHAR(5)));
使用 LEFT and RIGHT 字符串函数截断字符串:
INSERT INTO test VALUES(LEFT('abcdefghijkl', 5));
注意: CAST
应该是您的首选,因为它可以正确处理多字节字符。 LEFT
将根据 字符数 而不是 字节数 进行截断,如果您的字符串中有一个多字节字符,您可能最终超出了您的列的限制。
执行 INSERT 时,Redshift 不允许您插入比 table 中的目标字段 longer/wider 的字符串值。观察:
CREATE TEMPORARY TABLE test (col VARCHAR(5));
-- result: 'Table test created'
INSERT INTO test VALUES('abcdefghijkl');
-- result: '[Amazon](500310) Invalid operation: value too long for type character varying(5);'
一个解决方法是转换值:
INSERT INTO test VALUES('abcdefghijkl'::VARCHAR(5));
-- result: 'INSERT INTO test successful, 1 row affected'
令人讨厌的是,现在我的所有代码都必须像这样在每个 VARCHAR 字段的每个 INSERT 上使用这些强制转换语句,否则应用程序代码将不得不在尝试构造查询之前截断字符串;无论哪种方式,这都意味着列的宽度规范必须进入应用程序代码,这很烦人。
使用 Redshift 有更好的方法吗?如果有一些选项可以让服务器截断字符串并执行(并可能发出警告)与 MySQL.
相同的方式,那就太好了我可以做的一件事就是将这些特定字段声明为非常大的 VARCHAR,甚至可能是 65535(最大值)。
create table analytics.testShort (a varchar(3));
create table analytics.testLong (a varchar(4096));
create table analytics.testSuperLong (a varchar(65535));
insert into analytics.testShort values('abc');
insert into analytics.testLong values('abc');
insert into analytics.testSuperLong values('abc');
-- Redshift reports the size for each table is the same, 4 mb
我发现这种方法的一个缺点是如果在组中使用此列会导致性能不佳 by/join/etc:
https://discourse.looker.com/t/troubleshooting-redshift-performance-extensive-guide/326 (搜索 VARCHAR)
我想知道,如果您打算从不在 group by、join 等中使用此字段,是否没有其他危害。
在我的场景中需要注意的一些事情:是的,我真的不关心可能因截断而丢失的额外字符,不,我没有办法强制源文本的长度.我正在捕获来自外部来源的消息和 URL,它们的字符长度通常在一定范围内,但有时会有更长的字符。在我们的应用程序中,它们是否在存储中被截断并不重要。
自动截断字符串以匹配列宽的唯一方法是使用带有选项 TRUNCATECOLUMNS
的 COPY 命令Truncates data in columns to the appropriate number of characters so that it fits the column specification. Applies only to columns with a VARCHAR or CHAR data type, and rows 4 MB or less in size.
否则,您将不得不使用以下两种方法之一来处理字符串的长度:
将您的值显式转换为您想要的 VARCHAR:
INSERT INTO test VALUES(CAST('abcdefghijkl' AS VARCHAR(5)));
使用 LEFT and RIGHT 字符串函数截断字符串:
INSERT INTO test VALUES(LEFT('abcdefghijkl', 5));
注意: CAST
应该是您的首选,因为它可以正确处理多字节字符。 LEFT
将根据 字符数 而不是 字节数 进行截断,如果您的字符串中有一个多字节字符,您可能最终超出了您的列的限制。