This report presents YCSB (Yahoo! Cloud Serving Benchmark) benchmark results for PolarDB for PostgreSQL's DynamoDB-compatible API across five workload types and four data scales. Use these results for technology selection, application design, and capacity planning.
Point query performance peaks at 983,524 OPS (Operations Per Second) (64-core 256 GB specification, 10 GB data volume, 100% read workload).
Test environment
Environment configuration
|
Component |
Specifications |
|
Test cluster (PolarDB) |
|
|
Stress testing client (ECS) |
|
Benchmark tool
-
Metric: OPS (Operations Per Second) — the number of operations the database processes per second.
Workload model
All workloads use YCSB CoreWorkload. The test data model uses a single table usertable with a HASH primary key, and each record contains 10 fields of 100-byte random strings (approximately 1 KB per record).
|
YCSB workload |
Scenario |
Core parameter |
|
|
100% write |
|
|
|
100% update |
|
|
|
100% point query |
|
|
|
50% read + 50% update |
|
|
|
100% range scan |
|
Other stress testing methods
|
Stress testing method |
Description |
|
Data volume |
Preload 1 M / 10 M / 100 M / 1 B records respectively before running the stress test (approximately 1 GB / 10 GB / 100 GB / 1 TB of data). |
|
Test duration |
5 minutes per round (maxexecutiontime=300s) |
|
Value source |
The best throughput across different concurrent thread counts in the stress tests. |
Per-specification detailed test results
The following three tables show the throughput (OPS) for different data scales and workloads across three cluster specifications: 8-core 32 GB, 32-core 128 GB, and 64-core 256 GB. The best throughput across different concurrent thread counts in the stress tests is used.
8-core 32 GB specification
|
Test scenario |
1 GB (OPS) |
10 GB (OPS) |
100 GB (OPS) |
1 TB (OPS) |
|
100% read (Read) |
243,067 |
238,188 |
140,199 |
116,189 |
|
100% range scan (Scan) |
37,142 |
36,945 |
5,626 |
4,857 |
|
50% read + 50% update |
89,119 |
84,636 |
65,903 |
57,164 |
|
100% update (Update) |
45,401 |
42,869 |
34,741 |
29,907 |
|
100% write (Insert) |
57,806 |
46,621 |
44,428 |
44,359 |
32-core 128 GB specification
|
Test scenario |
1 GB (OPS) |
10 GB (OPS) |
100 GB (OPS) |
1 TB (OPS) |
|
100% read (Read) |
578,397 |
575,689 |
462,904 |
373,101 |
|
100% range scan (Scan) |
90,256 |
89,789 |
25,986 |
10,278 |
|
50% read + 50% update |
221,826 |
216,588 |
164,912 |
120,688 |
|
100% update (Update) |
114,770 |
114,696 |
92,479 |
78,317 |
|
100% write (Insert) |
128,332 |
121,148 |
117,396 |
112,275 |
64-core 256 GB specification
|
Test scenario |
1 GB (OPS) |
10 GB (OPS) |
100 GB (OPS) |
1 TB (OPS) |
|
100% read (Read) |
894,926 |
983,524 |
980,197 |
653,825 |
|
100% range scan (Scan) |
138,609 |
142,560 |
140,653 |
14,171 |
|
50% read + 50% update |
318,094 |
312,043 |
288,028 |
189,536 |
|
100% update (Update) |
171,349 |
170,789 |
154,085 |
115,961 |
|
100% write (Insert) |
171,682 |
176,069 |
167,877 |
165,308 |
Appendix: Reproduce the tests
Follow these steps to reproduce the performance tests for secondary validation or custom testing.
Step 1: Configure YCSB
Before running the tests, configure the YCSB DynamoDB client.
-
Configure identity credentials
Edit
dynamodb/conf/AWSCredentials.propertiesand enter the credentials for your PolarDB consolededicated 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
dynamodb/conf/dynamodb.propertiesand specify the PolarDB cluster connection information.# 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. Must include the http:// prefix. dynamodb.endpoint = http://<your-polardb-ddb-endpoint>:<port> # Leave the region parameter blank. dynamodb.region = # The primary key name and type for the test table. Must match the test table. dynamodb.primaryKey = HASH
Step 2: Patch the YCSB update operation
The official YCSB DynamoDB client uses the deprecated AttributeUpdates parameter by default. PolarDB requires the UpdateExpression parameter. You must apply the following change before running any update workloads.
-
File path:
dynamodb/src/main/java/site/ycsb/db/DynamoDBClient.java -
Method to modify:
update()
Replace the original implementation:
@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 change (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;
}
Step 3: Run the test
Each test run has two phases: load (populate test data) and run (execute the workload). The examples below use a 1 GB dataset (1 million records), 128 concurrent threads, and the read-only workload.
To test other data volumes, modify the recordcount and operationcount parameters in the commands.
-
Load data (Load Phase)
# -s: Displays status updates during loading. # -P workloads/workload_read_only: Specifies the workload file. # -P /path/to/dynamodb.properties: Specifies the database connection configuration. # -p recordcount=1000000: Total number of records to load (1 GB). # -p operationcount=1000000: Total number of operations. # -threads 128: 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 &