![[Update] Amazon Redshift's SUPER Data Type Can Now Store Strings of Up to 16,000,000 Bytes, So I Tried It Out](https://devio2024-media.developers.io/image/upload/f_auto,q_auto,w_3840/f_auto,q_auto/v1790870385/eyecatch/y1ipevknntjfjxlyd7ow.png)
[Update] Amazon Redshift's SUPER Data Type Can Now Store Strings of Up to 16,000,000 Bytes, So I Tried It Out
This page has been translated by machine translation. View original
I'm Ishikawa from the Cloud Business Division. Amazon Redshift's SUPER data type can now store individual strings of up to 16,000,000 bytes, so I tried it out on Amazon Redshift Serverless using the sample data from the AWS blog.
Amazon Redshift's SUPER data type can now store individual strings of up to 16,000,000 bytes. The previous limit was 65,535 bytes.
When you opt in with a database parameter, this limit applies to ingestion from JSON, PARQUET, TEXT, and CSV source files, as well as to transformations in ELT processing. You can now load JSON containing strings that exceed 65,535 bytes, such as contracts or long logs, without splitting or truncating them, and reference them with SQL. JSON_PARSE, CONCAT, and LISTAGG can also accept and output strings of up to 16,000,000 bytes.
It is available in all AWS Regions where Amazon Redshift is available, including the AWS GovCloud (US) Regions.
In this article, I enabled the parameter on a dedicated Amazon Redshift Serverless workgroup for testing, followed the steps in the AWS blog (loading JSON, string functions, and LISTAGG), and checked the limit with Japanese strings.
What is large string support in the SUPER data type
The SUPER data type is an Amazon Redshift data type that stores semi-structured data such as JSON without requiring a schema definition. It can hold arrays and nested structures as a single value, and elements within arrays and structures are referenced using PartiQL syntax. According to the documentation, each individual SUPER object supports up to 16 MB of data. What has been raised this time is the limit for each individual string contained in a SUPER value.
Large string support must be enabled with the parameter enable_large_strings_opt_in. The value can be Yes, No, or unset (the default); when unset, the existing behavior is maintained. The behavior for each value is as follows.
| Item | Yes |
No |
|---|---|---|
| Limit for individual strings in SUPER | 16,000,000 bytes | 65,535 bytes |
VARCHAR length that string functions can process |
Up to 16,000,000 bytes | Up to 65,535 bytes |
COPY / INSERT of more than 65,535 bytes into a SUPER column |
Possible | Not possible (existing strings can still be read as SUPER) |
CAST to VARCHAR(MAX) |
Treated as VARCHAR(16000000) |
Truncated to 65,535 bytes |
Column specified as VARCHAR(MAX) in CREATE TABLE |
VARCHAR(65535) |
VARCHAR(65535) |
The AWS blog lists Amazon Redshift Patch 206 or later (current maintenance track) as a prerequisite. For provisioned clusters, you set enable_large_strings_opt_in to Yes in a parameter group, attach it to the cluster, and reboot the cluster. Because Amazon Redshift Serverless does not use parameter groups, you specify the parameter in the workgroup settings. You can check the current state with SELECT is_large_string_enabled();.
The documentation and the AWS blog describe the following points to note.
- Once set to
YesorNo, it cannot be returned to the default (unset). Even if you reset withResetClusterParameterGroup, the configured value is retained - When the parameter is enabled,
VARCHAR(MAX)is treated asVARCHAR(16000000)within expressions such asCASTand views, but table columns are not affected. Even if you specifyVARCHAR(MAX)inCREATE TABLE, aVARCHAR(65535)column is created, so if you want to store in a table a string over 65,535 bytes extracted from a SUPER column, or the result ofLISTAGGor similar, store it in a SUPER column
One point that needs attention is that this parameter changes not only SUPER columns but also the upper limit of the VARCHAR length handled by string functions and casts. However, the limit is raised only for values handled within expressions; VARCHAR columns in tables are not affected.
- Views, UDFs, and stored procedures created before the parameter was enabled remain limited to 65,535 bytes until they are recreated
- If other views or objects depend on a view that uses
VARCHAR(MAX),CREATE OR REPLACE VIEWfails with the error "cannot change data type of view column". Drop the dependent objects, drop and recreate the view, and then recreate the dependent objects - If you use data sharing, make the settings consistent between the producer and consumer data warehouses
- If you restore a snapshot that contains strings over 65,535 bytes in a SUPER column to a cluster where this parameter is
No, ingestion of the long strings may fail
Trying it out
Prerequisites
- Region: Tokyo Region
- Amazon Redshift Serverless: Patch 206 (current track, workgroup version 1.0.535482), base capacity 4 RPU
- AWS CLI 2.39.5
- Sample data:
orders.jsondistributed in the AWS blog
Because enable_large_strings_opt_in cannot be returned to unset once configured, I did not use an existing workgroup and instead created a dedicated namespace and workgroup for this test. The flow of the test is as follows.
Creating the test environment
I built Redshift Serverless in the Tokyo Region with the following configuration.
| Resource | Name | Details |
|---|---|---|
| VPC and subnets | super16m-vpc, super16m-subnet-1 to 3 | Subnets in three Availability Zones. No internet gateway or NAT gateway |
| Security group | super16m-sg | No inbound rules |
| S3 bucket | super16m-<account ID>-ap-northeast-1 | Holds the test data for COPY |
| IAM role | super16m-copy-role | Allows read access to the test data bucket only. Set as the namespace's default IAM role |
| Namespace | super16m-ns | Database dev. The admin password is managed by Redshift in Secrets Manager |
| Workgroup | super16m-wg | Base capacity and max capacity both 4 RPU, no public access. Created without specifying enable_large_strings_opt_in |
The patch version and parameter of the created workgroup are as follows.
% aws redshift-serverless get-workgroup \
--workgroup-name super16m-wg \
--query "workgroup.{status:status,patchVersion:patchVersion,trackName:trackName,workgroupVersion:workgroupVersion,baseCapacity:baseCapacity,configParameters:configParameters[?parameterKey==\`enable_large_strings_opt_in\`]}"
{
"status": "AVAILABLE",
"patchVersion": "206",
"trackName": "current",
"workgroupVersion": "1.0.535482",
"baseCapacity": 4,
"configParameters": [
{
"parameterKey": "enable_large_strings_opt_in",
"parameterValue": ""
}
]
}
The patch version was 206, and the value of enable_large_strings_opt_in was an empty string (unset).
You can also confirm Patch 206 and Track Current on the workgroup screen in the Management Console.

Note that on the console's workgroup screen, I could not find any item to view or set enable_large_strings_opt_in in either the actions menu (delete workgroup, edit track, manage usage limits, etc.) or the six tabs (Query and database monitoring, Data access, Limits, Performance, Tags, Autonomics). For this reason, I changed and checked the parameter with the AWS CLI.
Enabling large string support
In Amazon Redshift Serverless, you change the parameter (enable_large_strings_opt_in) with --config-parameters of update-workgroup.
% aws redshift-serverless update-workgroup \
--workgroup-name super16m-wg \
--config-parameters parameterKey=enable_large_strings_opt_in,parameterValue=Yes \
--query "workgroup.{status:status,configParameters:configParameters[?parameterKey==\`enable_large_strings_opt_in\`]}"
{
"status": "MODIFYING",
"configParameters": [
{
"parameterKey": "enable_large_strings_opt_in",
"parameterValue": "Yes"
}
]
}
The status changed to MODIFYING, and when I checked at 10-second intervals, it returned to AVAILABLE after about 1 minute 45 seconds.
% aws redshift-serverless get-workgroup \
--workgroup-name super16m-wg \
--query "workgroup.{status:status,configParameters:configParameters[?parameterKey==\`enable_large_strings_opt_in\`]}"
{
"status": "AVAILABLE",
"configParameters": [
{
"parameterKey": "enable_large_strings_opt_in",
"parameterValue": "Yes"
}
]
}
Comparing the entire configParameters before and after the change, only enable_large_strings_opt_in had changed; the other parameters (auto_mv, datestyle, require_ssl, max_query_execution_time, etc.) retained their previous values.
How the SQL was run
First, check the state of large string support.
SELECT is_large_string_enabled();
% aws redshift-data get-statement-result --id aebe60e7-2a69-4e80-bb08-139b7d5e7568
{
"Records": [
[
{
"booleanValue": true
}
]
],
"ColumnMetadata": [
{
"isCaseSensitive": false,
"isCurrency": false,
"isSigned": false,
"label": "is_large_string_enabled",
"name": "is_large_string_enabled",
"nullable": 1,
"precision": 1,
"scale": 0,
"schemaName": "",
"tableName": "",
"typeName": "bool",
"length": 0
}
],
"TotalNumRows": 1
}
is_large_string_enabled() returned true. From here on, I present the SQL that was run and the results of get-statement-result summarized in tables. If an error occurred, I present the contents of Error from describe-statement.
Loading JSON containing large strings
I use the sample orders.json distributed in the AWS blog.
The file size is 3,203,661 bytes, and it contains 5 order records (JSON objects). In each order, detailedDescription is a string of 242,400 bytes and transactionLogs is a string of 397,600 bytes (both ASCII characters only), and both exceed 65,535 bytes. I upload this file to S3.
% aws s3 cp orders.json s3://super16m-123456789012-ap-northeast-1/testdata/orders.json --no-progress
upload: ./orders.json to s3://super16m-123456789012-ap-northeast-1/testdata/orders.json
As in the AWS blog's example, I create a table with a single SUPER column and COPY with FORMAT JSON 'noshred'.
CREATE TABLE orders (data SUPER);
COPY orders
FROM 's3://super16m-123456789012-ap-northeast-1/testdata/orders.json'
IAM_ROLE 'arn:aws:iam::123456789012:role/super16m-copy-role'
FORMAT JSON 'noshred';
The COPY completed without errors. I check the load result in SYS_LOAD_HISTORY.
SELECT query_id, status, TRIM(table_name) AS table_name, file_format,
loaded_rows, loaded_bytes, source_file_count, error_count
FROM sys_load_history
WHERE table_name = 'orders'
ORDER BY start_time DESC LIMIT 1;
| query_id | status | table_name | file_format | loaded_rows | loaded_bytes | source_file_count | error_count |
|---|---|---|---|---|---|---|---|
| 203099 | completed | orders | JSON | 5 | 3203661 | 1 | 0 |
5 rows were loaded. I check the contents of the loaded data. Because the JSON attribute names are camelCase, I set enable_case_sensitive_super_attribute to true before referencing them.
SET enable_case_sensitive_super_attribute TO true;
SELECT data.orderId::VARCHAR AS order_id,
data.customerId::VARCHAR AS customer_id,
data.status::VARCHAR AS status,
data.shippingAddress.state::VARCHAR AS shipping_state,
LENGTH(data.detailedDescription::VARCHAR) AS description_length,
LENGTH(data.transactionLogs::VARCHAR) AS logs_length
FROM orders
ORDER BY 1;
| order_id | customer_id | status | shipping_state | description_length | logs_length |
|---|---|---|---|---|---|
| ORD-2024-001 | CUST-12346 | processing | NY | 242400 | 397600 |
| ORD-2024-002 | CUST-12347 | processing | CA | 242400 | 397600 |
| ORD-2024-003 | CUST-12348 | processing | IL | 242400 | 397600 |
| ORD-2024-004 | CUST-12349 | processing | TX | 242400 | 397600 |
| ORD-2024-005 | CUST-12350 | processing | AZ | 242400 | 397600 |
The strings of 242,400 and 397,600 characters, which exceed 65,535 bytes, were stored without being truncated.
Use string functions after casting to VARCHAR
The AWS blog presents an example where applying a string function directly to a SUPER column value causes an error, and an example where it is applied after casting to VARCHAR. First, I try applying lower directly to a SUPER value.
SET enable_case_sensitive_super_attribute TO true;
SELECT lower(data.customerId) AS customer_id FROM orders;
ERROR: function lower(super) does not exist
Hint: No function matches the given name and argument types. You may need to add explicit type casts.
It resulted in an error because the lower function has no definition that accepts a SUPER-type argument. Since customerId is a 10-byte string, this error occurs regardless of string length. I apply it after casting to VARCHAR.
SET enable_case_sensitive_super_attribute TO true;
SELECT lower(data.customerId::VARCHAR) AS customer_id FROM orders ORDER BY 1;
| customer_id |
|---|
| cust-12346 |
| cust-12347 |
| cust-12348 |
| cust-12349 |
| cust-12350 |
After casting, the values converted to lowercase were returned. I also try applying string functions, after casting, to detailedDescription and transactionLogs, which exceed 65,535 bytes.
SET enable_case_sensitive_super_attribute TO true;
SELECT data.orderId::VARCHAR AS order_id,
LENGTH(lower(data.detailedDescription::VARCHAR)) AS lower_desc_length,
LENGTH(upper(data.transactionLogs::VARCHAR)) AS upper_logs_length,
RIGHT(upper(data.transactionLogs::VARCHAR), 30) AS upper_logs_tail
FROM orders
ORDER BY 1;
| order_id | lower_desc_length | upper_logs_length | upper_logs_tail |
|---|---|---|---|
| ORD-2024-001 | 242400 | 397600 | Z - DELIVERY DATE CALCULATED. |
| ORD-2024-002 | 242400 | 397600 | Z - DELIVERY DATE CALCULATED. |
| ORD-2024-003 | 242400 | 397600 | Z - DELIVERY DATE CALCULATED. |
| ORD-2024-004 | 242400 | 397600 | Z - DELIVERY DATE CALCULATED. |
| ORD-2024-005 | 242400 | 397600 | Z - DELIVERY DATE CALCULATED. |
The lengths of the lower and upper results were the same as the original strings, 242,400 and 397,600 characters, and the last 30 characters were returned converted to uppercase. Strings exceeding 65,535 bytes were also processed without being truncated.
Storing the string concatenated with LISTAGG in a SUPER column
Using the same query as the AWS blog, I concatenate the 5 detailedDescription values with LISTAGG and check the number of characters in the result.
SET enable_case_sensitive_super_attribute TO true;
SELECT LEN(LISTAGG(data.detailedDescription::VARCHAR, ', ')
WITHIN GROUP (ORDER BY data.orderId::VARCHAR)) AS description_length
FROM orders
WHERE data.status::VARCHAR = 'processing';
| description_length |
|---|
| 1212008 |
As stated in the AWS blog, the result was 1,212,008 characters (242,400 characters × 5 items, plus the 2-character delimiter , × 4 places).
The AWS blog explains that when the result of LISTAGG exceeds the 65,535-byte limit of a VARCHAR column, it can be stored in a SUPER column. I create tables with a SUPER column and a VARCHAR(MAX) column, and try storing the LISTAGG result in each.
CREATE TABLE order_desc_super (descriptions SUPER);
CREATE TABLE order_desc_varchar (descriptions VARCHAR(MAX));
SET enable_case_sensitive_super_attribute TO true;
-- Store in a SUPER column
INSERT INTO order_desc_super
SELECT LISTAGG(data.detailedDescription::VARCHAR, ', ') WITHIN GROUP (ORDER BY data.orderId::VARCHAR)
FROM orders WHERE data.status::VARCHAR = 'processing';
-- Store in a VARCHAR(MAX) column
INSERT INTO order_desc_varchar
SELECT LISTAGG(data.detailedDescription::VARCHAR, ', ') WITHIN GROUP (ORDER BY data.orderId::VARCHAR)
FROM orders WHERE data.status::VARCHAR = 'processing';
The INSERT into the SUPER column succeeded, and the INSERT into the VARCHAR(MAX) column resulted in the following error.
ERROR: Value too long for character type
Detail:
-----------------------------------------------
error: Value too long for character type
code: 8001
context: Value too long for type character varying(65535)
...
I check the value stored in the SUPER column and the definition of the VARCHAR(MAX) column.
SELECT JSON_TYPEOF(descriptions) AS type,
LEN(descriptions::VARCHAR) AS chars,
OCTET_LENGTH(descriptions::VARCHAR) AS bytes
FROM order_desc_super;
| type | chars | bytes |
|---|---|---|
| string | 1212008 | 1212008 |
SELECT table_name, column_name, data_type, character_maximum_length
FROM svv_columns
WHERE table_schema = 'public' AND table_name = 'order_desc_varchar';
| table_name | column_name | data_type | character_maximum_length |
|---|---|---|---|
| order_desc_varchar | descriptions | character varying | 65535 |
In the SUPER column, it was stored as a string of 1,212,008 bytes. The column created with VARCHAR(MAX) after enabling the parameter was character varying(65535), and values exceeding 65,535 bytes could not be stored.
Checking with Japanese strings
I check whether the limit is judged by character count or byte count, using a Japanese hiragana character that takes 3 bytes in UTF-8. Since 16,000,000 ÷ 3 = 5,333,333 remainder 1, adding one ASCII a to 5,333,333 of those hiragana characters gives 16,000,000 bytes.
I create a table for verification.
CREATE TABLE t_super (id INT, label VARCHAR(50), doc SUPER);
I check the character count and byte count of the strings to be stored.
SELECT LEN(REPEAT('あ', 5333333) || 'a') AS chars_a,
OCTET_LENGTH(REPEAT('あ', 5333333) || 'a') AS bytes_a,
LEN(REPEAT('あ', 5333334)) AS chars_b,
OCTET_LENGTH(REPEAT('あ', 5333334)) AS bytes_b;
| chars_a | bytes_a | chars_b | bytes_b |
|---|---|---|---|
| 5333334 | 16000000 | 5333334 | 16000002 |
Both are 5,333,334 characters, and only the byte counts differ. I try storing each with JSON_PARSE.
INSERT INTO t_super VALUES (20, 'ja-16000000', JSON_PARSE('{"body":"' || REPEAT('あ', 5333333) || 'a' || '"}'));
INSERT INTO t_super VALUES (21, 'ja-16000002', JSON_PARSE('{"body":"' || REPEAT('あ', 5333334) || '"}'));
id=20 at 16,000,000 bytes succeeded, and id=21 at 16,000,002 bytes resulted in the following error.
ERROR: Invalid input
Detail:
-----------------------------------------------
error: Invalid input
code: 8001
context: JSON_PARSE() error: String value exceeds the max size of 16000000 bytes: (16000000 bytes skipped) "}
...
I check the stored value.
SELECT id, label, LEN(doc.body::VARCHAR) AS chars, OCTET_LENGTH(doc.body::VARCHAR) AS bytes,
SUBSTRING(doc.body::VARCHAR, 1, 5) AS head5
FROM t_super WHERE id >= 20 ORDER BY id;
| id | label | chars | bytes | head5 |
|---|---|---|---|---|
| 20 | ja-16000000 | 5333334 | 16000000 | (five hiragana characters) |
The limit is judged by byte count. For a string consisting only of Japanese (3-byte characters), the limit is about 5.33 million characters.
Checking in Query Editor v2
I also checked is_large_string_enabled() and the LISTAGG result in Query Editor v2 in the Management Console (connected as a federated user).
SET enable_case_sensitive_super_attribute TO true;
SELECT is_large_string_enabled() AS large_string_enabled,
COUNT(*) AS orders,
LEN(LISTAGG(data.detailedDescription::VARCHAR, ', ')
WITHIN GROUP (ORDER BY data.orderId::VARCHAR)) AS description_length
FROM orders
WHERE data.status::VARCHAR = 'processing';

large_string_enabled was true, orders was 5, and description_length was 1,212,008, the same as with the Data API.
Discussion
The results confirmed in this verification are summarized below.
| What was checked | Result |
|---|---|
| Parameter change (Serverless) | About 1 minute 45 seconds with update-workgroup. Other parameters kept their previous values |
is_large_string_enabled() |
true |
COPY of orders.json (FORMAT JSON 'noshred') |
Loaded 5 rows containing strings of 242,400 bytes and 397,600 bytes |
Applying lower directly to a SUPER value |
function lower(super) does not exist error |
Applying lower / upper after casting to ::VARCHAR |
Processed at 242,400 and 397,600 characters as is |
LISTAGG result |
1,212,008 characters (same as the AWS blog) |
Storing the LISTAGG result |
Succeeded for the SUPER column, error for the VARCHAR(MAX) column (character varying(65535)) |
Japanese strings (JSON_PARSE) |
16,000,000 bytes (5,333,334 characters) succeeded, 16,000,002 bytes (5,333,334 characters) errored |
Based on these results, I think the following points need attention.
- In Amazon Redshift Serverless, setting and checking the parameter is done via the CLI or similar. The workgroup screen in the console that I checked had no item to view or set
enable_large_strings_opt_in. You can check the value after setting it withconfigParametersofget-workgroup, or withSELECT is_large_string_enabled(); - When applying string functions to SUPER values, cast to
::VARCHAR. The error without a cast is due to the function's argument type, and occurred even for short strings. With the cast, the result length was the same as the original string even for strings over 65,535 bytes - To save values over 65,535 bytes in a table, use a SUPER column. Even after enabling the parameter, a column specified as
VARCHAR(MAX)inCREATE TABLEischaracter varying(65535), and theLISTAGGresult (1,212,008 bytes) could not be stored - The limit is in bytes, not characters. For a string consisting only of Japanese characters at 3 bytes each in UTF-8, the limit is about 5.33 million characters. When estimating the length of data that includes Japanese, you need to check the byte count with
OCTET_LENGTHrather than the character count - Because the parameter cannot be returned to unset, I recommend trying it first in a dedicated test environment before using an existing environment. In this Amazon Redshift Serverless test, creating the test environment took about 1 minute 50 seconds and changing the parameter took about 1 minute 45 seconds
This verification did not cover provisioned clusters (parameter groups and cluster reboot), behavior before enabling the parameter, behavior when set to No, recreation of existing views, UDFs, and stored procedures, data sharing, snapshot restore, or COPY from PARQUET, TEXT, and CSV.
Conclusion
Amazon Redshift's SUPER data type can now store individual strings of up to 16,000,000 bytes. By setting enable_large_strings_opt_in to Yes in Amazon Redshift Serverless, I confirmed that the AWS blog's sample orders.json (JSON containing strings of 242,400 bytes and 397,600 bytes) can be loaded as is into a SUPER column with COPY, and that string functions applied after casting to VARCHAR, as well as LISTAGG, handle strings over 65,535 bytes without truncation.
On the other hand, VARCHAR(MAX) columns in tables remain at 65,535 bytes, and the limit is judged in bytes. There are also points to check before enabling, such as the fact that once set it cannot be returned to the default, and that existing views, UDFs, and stored procedures need to be recreated. If you are currently splitting or truncating JSON to fit the 65,535-byte limit, why not consider adopting this after enabling the parameter in a dedicated test environment and checking the impact on your existing load processes and objects?
