This report presents the performance benchmark results for PolarDB for PostgreSQL across typical workloads, based on the de facto standard Yahoo! Cloud Serving Benchmark (YCSB). It provides quantitative data to assist with technology selection, application design, and capacity planning. The results demonstrate stable, high-performance read and write capabilities across various data scales. This feature performs exceptionally well in point query (Point Lookup) scenarios. With a 100 GB data volume, the peak performance can reach 109,808 Operations Per Second (OPS).
Test result summary
The following table shows the peak performance (OPS) for each test model at different data volumes.
Test scenario | 1 GB data volume (OPS) | 10 GB data volume (OPS) | 100 GB data volume (OPS) | 1 TB data volume (OPS) |
100% write (Insert) | 41,430 | 39,861 | 33,357 | 36,248 |
100% update (Update) | 44,177 | 41,486 | 38,062 | 30,782 |
100% read (Read) | 80,573 | 82,856 | 109,808 | 75,108 |
50% read + 50% update | 45,010 | 42,962 | 39,805 | 32,021 |
100% range scan (Scan) | 1,073 | 1,089 | 1,075 | 922 |
The results above are the peak performance values obtained from tests conducted at various concurrency levels.
Test method and environment
Environment configuration
Component | Specifications and configuration |
Test cluster (PolarDB) |
|
Stress testing client (ECS) |
|
Deployment region | Beijing, Zone K |
Benchmark tool
Performance metric: OPS (Operations Per Second), which is the number of operations the database processes per second.
Workload model
Five typical business scenarios are simulated by configuring the YCSB CoreWorkload. The test data model uses records that each contain 10 fields. Each field has a value with a length of 100 bytes, meaning each record is approximately 1 KB in size.
YCSB Workload | Scenario description | Core parameter configuration |
| 100% write |
|
| 100% update |
|
| 100% point query |
|
| 50% read + 50% update |
|
| 100% range query |
|
Appendix: Test steps
This appendix details the steps to reproduce the performance tests. You can use these steps for secondary authentication or for customized testing.
1. Configure YCSB
Before you run the test, you must configure the YCSB DynamoDB client.
Configure identity credentials
Edit the
dynamodb/conf/AWSCredentials.propertiesfile. Enter the identity credentials for the dedicated DynamoDB account that you created in the PolarDB consoleCreate a dedicated DynamoDB account.# The account name is the AccessKey ID accessKey = <YOUR_ACCESS_KEY_ID> # Secret key secretKey = <YOUR_SECRET_ACCESS_KEY>Configure connection properties
Edit the
dynamodb/conf/dynamodb.propertiesfile to specify the connection information for the PolarDB clusterConfigure a DynamoDB endpoint.# The absolute path of the authentication file dynamodb.awsCredentialsFile = /path/to/your/AWSCredentials.properties # Create a usertable table in the cluster in advance. This example creates a usertable table with only a partition key named pk. dynamodb.primaryKey = pk # The DynamoDB endpoint for PolarDB. It must include the http:// prefix. dynamodb.endpoint = http://<your-polardb-ddb-endpoint>:<port> # The region parameter must be set to empty. dynamodb.region = # The primary key name and type for the test table. They must be consistent with the test table. dynamodb.primaryKey = HASH
2. Adapt the YCSB Update operation
The official YCSB DynamoDB client uses the deprecated AttributeUpdates parameter to perform updates by default. To ensure compatibility with the new UpdateExpression parameter supported by PolarDB, you must modify the YCSB source code.
File path:
dynamodb/src/main/java/site/ycsb/db/DynamoDBClient.javaMethod to modify:
update()
Original code
@Override
public Status update(String table, String key, Map<String, ByteIterator> values) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("updatekey: " + key + " from table: " + table);
}
Map<String, AttributeValueUpdate> attributes = new HashMap<>(values.size());
for (Entry<String, ByteIterator> val : values.entrySet()) {
AttributeValue v = new AttributeValue(val.getValue().toString());
attributes.put(val.getKey(), new AttributeValueUpdate().withValue(v).withAction("PUT"));
}
UpdateItemRequest req = new UpdateItemRequest(table, createPrimaryKey(key), attributes);
try {
dynamoDB.updateItem(req);
} catch (AmazonServiceException ex) {
LOGGER.error(ex);
return Status.ERROR;
} catch (AmazonClientException ex) {
LOGGER.error(ex);
return CLIENT_ERROR;
}
return Status.OK;
}After the update (using UpdateExpression)
@Override
public Status update(String table, String key, Map<String, ByteIterator> values) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("updatekey: " + key + " from table: " + table);
}
StringBuilder updateExp = new StringBuilder("SET ");
Map<String, String> attrNames = new HashMap<>();
Map<String, AttributeValue> attrValues = new HashMap<>();
boolean first = true;
for (Map.Entry<String, ByteIterator> entry : values.entrySet()) {
String attr = entry.getKey();
if (!first) {
updateExp.append(", ");
}
String attrName = "#" + attr;
String valueName = ":" + attr;
updateExp.append(attrName).append(" = ").append(valueName);
attrNames.put(attrName, attr);
attrValues.put(valueName, new AttributeValue(entry.getValue().toString()));
first = false;
}
UpdateItemRequest req = new UpdateItemRequest()
.withTableName(table)
.withKey(createPrimaryKey(key))
.withUpdateExpression(updateExp.toString())
.withExpressionAttributeNames(attrNames)
.withExpressionAttributeValues(attrValues);
try {
dynamoDB.updateItem(req);
} catch (AmazonServiceException ex) {
LOGGER.error(ex);
return Status.ERROR;
} catch (AmazonClientException ex) {
LOGGER.error(ex);
return CLIENT_ERROR;
}
return Status.OK;
}3. Run the test
The test is divided into two phases: load (to load the initial data) and run (to run the workload). The following example is for a test with a data volume of 1 GB (1 million records), 128 concurrent threads, and a read-only model:
To test with different data volumes, you can modify the recordcount and operationcount parameters in the command.
Load data (Load Phase)
# Description: # -s: Displays status updates. # -P workloads/workload_read_only: Specifies the base workload file. # -P /path/to/dynamodb.properties: Specifies the database connection configuration file. # -p recordcount=1000000: Defines the total number of records. # -p operationcount=1000000: Defines the total number of operations to run. # -threads 128: Specifies the number of concurrent threads. nohup ./bin/ycsb load dynamodb -s \ -P workloads/workload_read_only \ -P /path/to/dynamodb.properties \ -p recordcount=1000000 \ -p operationcount=1000000 \ -threads 128 \ > load.log 2>&1 &Run the test (Run Phase)
nohup ./bin/ycsb run dynamodb -s \ -P workloads/workload_read_only \ -P /path/to/dynamodb.properties \ -p recordcount=1000000 \ -p operationcount=1000000 \ -threads 128 \ > run.log 2>&1 &