比较Amazon Aurora、Redshift和DynamoDB在不同工作负载下的性能
首先
AWS提供的主要数据库服务包括:专为云计算设计的关系型数据库Amazon Aurora,专注于数据分析的关系型数据库Amazon Redshift,以及宽列数据库(NoSQL)Amazon DynamoDB1。通常,根据AWS的各个数据库服务的用途,可以使用Aurora或DynamoDB作为业务系统的数据库,使用Redshift作为分析系统的数据库2。为了定量地确认这一观点的依据,我决定对不同的OLTP/OLAP工作负载施加压力,以检查各个数据库服务在性能特性方面的差异。
实际系统性能会受到各种条件的影响而变动,请将其仅视为参考信息之一。
基本概念
首先作为一个前提,我们来概述一下OLTP/OLAP工作负载。OLTP/OLAP是在数据仓库和商业智能领域中经常出现的概念,它对处理数据库的内容进行了分类。下图是一张示意图,图中箭头的数量表示SQL的执行频率,箭头的大小表示单个SQL的负载大小。

OLTP (Online Transaction Processing | オンライントランザクション処理)
主に業務系システムから定常的に実行される、単一行の参照/更新/挿入/削除処理。
SQLクエリの典型例: SELECT … FROM A WHERE id = N; UPDATE A SET value = ‘x’ WHERE id = N; INSERT INTO A VALUES (…); DELETE FROM A WHERE id = N;
OLAP (Online Analytical Processing | オンライン分析処理)
主に分析系システムから一時的に実行される、(表結合を伴う)大量データの集計処理。
SQLクエリの典型例: SELECT …, SUM(A.z) FROM A INNER JOIN B ON … INNER JOIN C ON … GROUP BY …;
由于OLTP和OLAP工作负载对数据库的性能要求不同,因此在系统设计中,可能会根据不同的工作负载使用多个数据库。顺便提一下,以前只有本地环境,为了满足OLAP的性能要求,我们会引入与硬件集成的昂贵的DWH应用设备,或者进行常规的Oracle数据库微调。
测量方法
这次我们将使用以下方法来测量不同工作负载下的DB性能。
OLTP工作负载的设计
我們將執行一個包含十萬條單行插入查詢的操作,並測量處理能力(每分鐘的插入數量)。
INSERT INTO order_details (order_id, item_id, sales_price, amount)
VALUES (:order_id, :item_id, :sales_price, :amount);
CREATE TABLE order_details( -- 注文明細表
order_id int NOT NULL, -- 注文ID
item_id int NOT NULL, -- 商品ID
sales_price int NOT NULL, -- 売値
amount int NOT NULL, -- 数量
PRIMARY KEY (order_id, item_id) -- 主キー
);
以下是数据库的测量对象。3
-
- Aurora Serverless
PostgreSQL 10.7
MySQL 5.6.10a
DynamoDB on-demand
Redshift
ra3.4xlarge (12 vCPU, メモリ 96GiB, 2ノード)
OLAP工作负载的设计
发出一条SQL查询以汇总以下5个数据,并测量响应时间。
CREATE TABLE sales_order(
order_id int NOT NULL, -- 注文ID
timestamp timestamp NOT NULL, -- 日時
store_id int NOT NULL, -- 店舗ID
customer_id int NOT NULL, -- 顧客ID
total_price int, -- 合計金額
PRIMARY KEY (order_id) -- 主キー
)
sortkey(store_id, timestamp) -- ソートキー(Redshiftのみ)
;
SELECT store_id, date_trunc('month', timestamp) as month, SUM(total_price) as sales_by_month FROM sales_order GROUP BY store_id, month;
我们将DB作为测试对象。
-
- Aurora
PostgreSQL 11.6 db.r5.4xlarge (16 vCPU, 128 GiB)
Redshift
ra3.4xlarge (12 vCPU, メモリ 96GiB, 2ノード)
实时事务处理的测量结果
首先,我们将发布OLTP工作负载性能比较的测量结果。
通量比较
下图是行插入工作负载吞吐量(件/秒)的测量结果。吞吐量越高,性能越好。对于承受负载的服务器,我们使用了将资源设置为最大的AWS Lambda。为了接近其他数据库的条件,我们使用了Data API和DB适配器(psycopg2)两种连接方法来进行测量。

-
- 並列度(p)は、負荷かけスクリプトの挿入クエリの同時実行数。詳細は付録のスクリプトを参照。
- Aurora Serverlessのキャパシティユニット(ACU)5は、いずれも2 ACUで計測。
当查看结果图表时,我们发现 Aurora Serverless(Data API)和 DynamoDB 在并行度为 10-15 的范围内,吞吐量达到了瓶颈。这不是数据库的问题,而是由于 HTTP API 在负载服务器端的 CPU 负载较重,导致负载服务器端(Lambda)的 CPU 负载成为瓶颈。至于 Redshift,在并行度为 1 的情况下,已经达到了 Redshift 的性能极限(约为 15 条/秒)。
测量环境.
当测试吞吐量性能时,系统环境如下图所示。由于DynamoDB无法部署在VPC内,我们通过VPC终端节点进行配置,以实现在不经过互联网的情况下进行通信。

请参考文章末尾的附录,了解有关负载脚本内容和Lambda函数设置的详细信息。
成本比较
以下是各个数据库服务每小时成本比较的表格。由于DynamoDB On-Demand的费用会根据写入数量变动,因此为了比较,我们将吞吐量1件/秒转换为1 WCU7,并记录了预配置容量的费用。Aurora Serverless记录了计量时的容量单位(2 ACU5)的费用。
(1WCU=1件/sec, Provisioned)Aurora Serverless (2 ACU)Redshift ra3.x4largep=1(89 WCU)
0.06 USD/hour0.12 USD/hour3.38 USD/hourp=2(174 WCU)
0.12 USD/hour0.12 USD/hour3.38 USD/hourp=5(434 WCU)
0.32 USD/hour0.12 USD/hour3.38 USD/hourp=10(482 WCU)
0.35 USD/hour0.12 USD/hour3.38 USD/hourp=15(578 WCU)
0.42 USD/hour0.12 USD/hour3.38 USD/hour
-
- 2020年6月時点の東京リージョン(asia-northeast1)の料金。
-
- 小数点第3位以下は切り捨て。
- インスタンス以外にかかる料金(ストレージ容量やIO課金)は一旦無視。
根据对比表可以看出,如果每秒钟持续发生大约200个以上的插入查询,Aurora Serverless似乎可以更节省成本。然而,如果不是持续的负载,似乎DynamoDB更具有灵活的定价结构,可以节省成本。
确认的事情
RedshiftのOLTP性能(挿入系)は、約15件/秒が限界。
Auroraでは並列度を上げると秒間1,000件以上の挿入クエリを捌けた一方で、Redshift ra3.x4largeでは約15件/秒で頭打ちになってしまった。
RedshiftのCPU利用率が2ノードとも約20%で張り付いていたため、Redshiftのリソース制限に引っ掛かったと思われる。
DBアダプタ経由とHTTP API経由のDB接続方法で、負荷かけサーバのCPU利用率が10倍以上異なる。
HTTP経由のクエリ(DynamoDB APIとAurora Data API)は、並列度10-15でLambda側の限界でスループット性能が頭打ちになった。
並列度10-15では、Aurora Data APIではCPU利用率90-100%となっていた一方で、psycopg2では10%以下で推移していた。
如果Lambda不成为性能瓶颈的话,我认为DynamoDB的性能上限应该比Aurora Serverless更高(几乎无限),但这次我们没有承受那么大的负载。Redshift尽管拥有丰富的资源,但很快性能就达到了瓶颈。
OLAP 数据分析结果
现在OLTP部分已经结束,接下来我们将比较OLAP工作负载的性能。Redshift的OLTP工作负载(插入计算)结果不太理想,但是由于Redshift本身是专门为OLAP设计的数据库,所以我们期望它能在这方面发挥出真正的优势。
回应时间较短
这张图显示了OLAP查询的响应时间(秒)的测量结果。响应时间越短,性能越好。PostgreSQL的并行度是通过parallel_workers系列参数来控制的,查询并行度为8。

(索引なし,並列度1)Aurora db.r5.4xlarge
(索引あり,並列度2)Aurora db.r5.4xlarge
(索引なし,並列度2)Aurora db.r5.4xlarge
(索引なし,並列度7)Redshift ra3.x4large
(ソートキーなし)Redshift ra3.x4large
(ソートキーあり)1,000万件9.85 sec8.97 sec–0.05 sec0.05 sec5,000万件54.93 sec48.23 sec26.33 sec15.47 sec0.20 sec0.16 sec10,000万件116.98 sec96.56 sec59.62 sec37.95 sec0.38 sec0.31 sec25,000万件313.12 sec245.34 sec164.51 sec116.23 sec0.92 sec0.77 sec50,000万件653.19 sec486.53 sec361.54 sec262.33 sec1.76 sec1.46 sec
-
- Aurora PostgreSQLの並列度について、
索引ありの条件では、実行計画を並列実行(Parallel Index Scan)に誘導できなかったため並列度1のみ計測。
データ件数1,000万件の条件では、実行計画を並列実行(Parallel Seq Scan)に誘導できなかったため並列度1のみ計測。
最大並列度7について、デフォルトのパラメータグループでは並列度を8よりも大きい値に設定できなかったため、最大7(8 – 1管理接続用プロセス)で計測。
具有几乎相同系统规格的Aurora db.r5.4xlarge和Redshift ra3.x4large,但即使调优后,Aurora在对5亿条(5,0000万条)数据进行汇总时所需时间仍然超过4分钟,而Redshift可以在不到2秒的时间内完成。通过进一步提高查询并行度或引导索引并行扫描等额外的调优措施,可能可以稍微提高Aurora PostgreSQL的响应时间。然而,Redshift依然明显更快。
测量环境
执行了以下的汇总查询,并测量了响应时间。(测量时省略了ORDER BY子句)
> SELECT store_id, date_trunc('month', timestamp) as month, SUM(total_price) as sales_by_month FROM sales_order GROUP BY store_id, month ORDER BY store_id, month;
store_id | month | sales_by_month
----------+---------------------+----------------
0 | 2014-04-01 00:00:00 | 67222780
0 | 2014-05-01 00:00:00 | 72365720
0 | 2014-06-01 00:00:00 | 69271910
(..省略..)
99 | 2020-02-01 00:00:00 | 70760330
99 | 2020-03-01 00:00:00 | 66501940
時間: 26337.9245 ms
-
- psqlでDBにログインして\timing設定をonにし、SQL実行後に表示される時間を計測。
-
- キャッシュに乗った状態で計測するため、同じSQLを2回実行した2回目の結果を採用。
-
- PostgreSQLでは、max_parallel_workersとmax_parallel_workers_per_gatherのパラメータでクエリ並列度を制御。
-
- Redshiftでは、SET enable_result_cache_for_session = off;でリザルトキャッシュをOFFに設定。
参考:【Redshift】パフォーマンス計測時にはコードコンパイルとリザルトキャッシュに注意
索引规划
如果要设置B树索引或排序键,可以指定数据的物理布局按照store_id和timestamp的顺序排列,如下所示。
CREATE INDEX sales_order_idx_01
ON sales_order (store_id, date_trunc('month', timestamp), total_price);
由于在创建索引后执行大量数据生成SQL语句时,PostgreSQL的B-tree索引会花费很长时间,因此我们必须在数据生成后才能生成索引。而在Redshift中,我们可以在CREATE TABLE语句中指定排序键。
成本比较
以下是各个数据库服务每小时成本的比较表。
-
- 2020年6月時点の東京リージョン(asia-northeast1)の料金。
-
- 小数点第3位以下は切り捨て。
- インスタンス以外にかかる料金(ストレージ容量やIO課金)は一旦無視。
红移比奥罗拉更昂贵,但从性能比来看,红移的成本效益更好。
我确认了的事情
RedshiftのOLAP性能は、ほぼ同スペックのAurora PostgreSQLよりも数百倍以上高速。
Auroraでは4分以上かかる5億件(50,000万件)のデータ集計を、Redshiftでは2秒以下で完了。
Aurora for PostgreSQLはチューニングにより2倍以上高速化できたが、無チューニングのRedshiftに及ばない。
チューニング後でも、依然として100倍以上の応答時間の差がある。
设计要点(OLTP/OLAP 视角)
在设计数据分析基础架构时,我们将讨论如何应用OLTP/OLAP的理念,基于以上所述。
混合了OLTP和OLAP的系统
在存在OLTP / OLAP两种工作负载的系统中,通常需要考虑将数据库分离的架构,如下图所示。 OLTP数据库是指适用于DynamoDB或Aurora等OLTP工作负载的数据库,而OLAP数据库是指适用于Redshift等OLAP工作负载的数据库。

例如,在设计电子商务网站系统时,接收顾客订单的功能是OLTP工作负载,因此采用OLTP数据库的DynamoDB或Aurora;而汇总周销售和月销售的功能是OLAP工作负载,因此采用OLAP数据库的Redshift。采用这种数据库设计模式,可以充分发挥数据库的性能。
ETL还是ELT?
如果要将OLTP数据库和OLAP数据库分开设计,还需要考虑定期进行数据库间数据迁移的问题。在数据分析基础设施领域中,通常将这种数据库间数据迁移称为ETL(抽取、转换、加载)。ETL是提取(Extract)、转换(Transform)和加载(Load)三个步骤的缩写,但有时也会按照下图所示的顺序改成ELT(提取、加载、转换)。

ETL和ELT哪种方式更好,要根据具体情况而定。ETL方式具有较少对数据库性能资源的影响的优点,但同时也存在批处理服务器(如图中齿轮部分)处理能力容易成为瓶颈的缺点。当需要将大量数据迁移到OLAP数据库时,ETL的缺点更容易显现出来,因此可以考虑使用ELT方式来实现,并利用数据迁移目标OLAP数据库的数据处理能力,或者考虑使用类似AWS Glue这样具备数据处理能力的云端ETL服务。
HTAP 数据库
使用HTAP数据库(混合事务分析处理)将OLTP数据库和OLAP数据库的优点结合起来。据说使用HTAP数据库可以摆脱从OLTP数据库到OLAP数据库的ETL/ELT(数据迁移),从而能够实时使用数据进行数据分析,并享受相关好处。

然而,目前的HTAP技术在我所观察到的范围内并非完全无缺,现有产品也倾向于依赖于OLTP或OLAP的性能之一。因此,我个人认为,在目前的数据基础设施设计中,将OLTP数据库和OLAP数据库分开构建会更为稳妥。未来可能会出现更易用的HTAP数据库,因此我希望能关注未来的技术发展。
总结
我刚刚对Amazon Aurora、Redshift和DynamoDB进行了不同工作负载的性能测试。尤其是Redshift在OLTP/OLAP工作负载下的优劣非常明显,因此理解其特性并在适当的场景下使用非常重要。请不要仅仅因为它每秒只能处理15个事务而对其产生偏见,因为它还有更出色的优点。
支付附件
有关建立测量环境的稍微详细的内容将在附录中提及。
负载脚本(OLTP)
-
- OLTPワークロードのLambda用負荷かけスクリプト。
-
- スクリプト中のparallel変数の値で、クエリの並列実行数(pythonプログラムの同時実行プロセス数)を変更可能。
- 実行環境は全てPython 3.7を想定。
**DynamoDB** can be paraphrased in Chinese as **云数据库** .
- DynamoDB API(Boto3)を利用してDynamoDBに接続し、挿入クエリを発行する。
import boto3
import random
import time
from datetime import datetime
import multiprocessing
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('order_details') # 挿入先テーブル名
total_num = 100000 # 挿入件数 (可変)
parallel = 10 # 並列度 (可変)
# 親プロセス
def lambda_handler(event, context):
process_list = []
for i in range(parallel):
process_list.append(multiprocessing.Process(target=child_proc)) # 子プロセス生成
start_time = time.time() # 計測開始
for process in process_list:
process.start() # 子プロセス実行開始
for process in process_list:
process.join() # 子プロセス実行完了待ち合わせ
end_time = time.time() # 計測終了
result = {
'total_num': total_num,
'parallel': parallel,
'total time': "{:.2f}".format(end_time - start_time) + " sec",
}
print (result) # コンソール上にも出力
return result
# 子プロセス
def child_proc():
for i in range(int(total_num / parallel)): # (合計件数/並列度)回実行
table.put_item(
Item={
"order_id": int(random.random() * 1000000000), # 注文ID
"item_id": int(random.random() * 10000), # 商品ID
"sales_price": int(random.random() * 100) * 10, # 売値
"amount": int(random.random() * 100), # 数量
}
)
无服务器数据 API 的 Aurora
-
- Data API(Boto3)を利用してAurora Serverlessに接続し、挿入クエリを発行する。
- コード中のSECRET_ARNは、Amazon Secrets Managerで生成する。
import boto3
import random
import time
from datetime import datetime
import multiprocessing
total_num = 100000 # 挿入件数 (可変)
parallel = 10 # 並列度 (可変)
rds_data = boto3.client('rds-data')
resource_arn = 'arn:aws:rds:ap-northeast-1:999999999999:cluster:test'
secret_arn = 'arn:aws:secretsmanager:ap-northeast-1:999999999999:secret:test-xxxxxx'
sql = "INSERT INTO order_details (order_id, item_id, sales_price, amount) VALUES (:order_id, :item_id, :sales_price, :amount)"
# 親プロセス
def lambda_handler(event, context):
process_list = []
for i in range(parallel):
process_list.append(multiprocessing.Process(target=child_proc)) # 子プロセス生成
start_time = time.time() # 計測開始
for process in process_list:
process.start() # 子プロセス実行開始
for process in process_list:
process.join() # 子プロセス実行完了待ち合わせ
end_time = time.time() # 計測終了
result = {
'total_num': total_num,
'parallel': parallel,
'total time': "{:.2f}".format(end_time - start_time) + " sec",
}
print (result) # コンソール上にも出力
return result
# 子プロセス
def child_proc():
for i in range(int(total_num / parallel)): # (合計件数/並列度)回実行
parameters = [
{'name':'order_id','value':{'longValue':int(random.random() * 1000000000)}}, # 注文ID
{'name':'item_id','value':{'longValue':int(random.random() * 10000)}}, # 商品ID
{'name':'sales_price','value':{'longValue':int(random.random() * 100) * 10}}, # 売値
{'name':'amount','value':{'longValue':int(random.random() * 100)}}, # 数量
]
try:
response = rds_data.execute_statement(
resourceArn = resource_arn,
secretArn = secret_arn,
database = 'sales',
sql = sql,
parameters = parameters
)
if response["ResponseMetadata"]["HTTPStatusCode"] != 200:
print(response)
except Exception as e:
print(e) # 一意制約違反等のエラーを出力
PostgreSQL和Redshift
-
- PostgreSQL向けDBアダプタのpsycopg2を利用して、AuroraまたはRedshiftに接続して挿入クエリを発行する。
- 正規のpsycopg2のライブラリをそのままLambdaにアップロードして実行するとエラーとなっため、awslambda-psycopg2を利用。
import psycopg2
import random
import time
from datetime import datetime
import multiprocessing
sql = "INSERT INTO order_details (order_id, item_id, sales_price, amount) VALUES (%s,%s,%s,%s)"
total_num = 100000 # 挿入件数 (可変)
parallel = 10 # 並列度 (可変)
# 接続情報
def get_connection():
return psycopg2.connect(host="db-name.xxxxxxxxxxxx.ap-northeast-1.<rds/redshift>.amazonaws.com", port=<5432/5439>, user="admin", password="xxxxxxxxxxxx", dbname="sales")
# 親プロセス
def lambda_handler(event, context):
process_list = []
for i in range(parallel):
process_list.append(multiprocessing.Process(target=child_proc)) # 子プロセス生成
start_time = time.time() # 計測開始
for process in process_list:
process.start() # 子プロセス実行開始
for process in process_list:
print(process.join()) # 子プロセス実行完了待ち合わせ
end_time = time.time() # 計測終了
result = {
'total_num': total_num,
'parallel': parallel,
'total time': "{:.2f}".format(end_time - start_time) + " sec",
}
print (result) # コンソール上にも結果を出力
return result
# 子プロセス
def child_proc():
with get_connection() as conn:
for j in range(int(total_num / parallel)): # (合計件数/並列度)回実行
order_id = int(random.random() * 1000000000) # 注文ID
item_id = int(random.random() * 10000) # 商品ID
sales_price = int(random.random() * 100) * 10 # 売値
amount = int(random.random() * 100) # 数量
try:
with conn.cursor() as cur:
cur.execute(sql, (order_id, item_id, sales_price, amount))
conn.commit()
except Exception as e:
print(type(e), e) # 一意制約違反等のエラーを出力
设定Lambda函数
将Lambda函数的参数设置从默认值更改为以下值。
-
- メモリ割当: 3,008MB(最大)
-
- 実行時間: 15分(最大)
-
- 同時実行数の予約: 1
- 非同期呼び出しの再試行数: 0
如果将内存分配设置为最大值,则相应的CPU资源也将达到最大值(根据官方文档)。如果不进行此设置,则在调用API操作时可能会失败,造成错误消息:Network Error(或Rate Exceeded)的错误,并可能导致Lambda函数重新执行。由于无法从Lambda的UI上确认完成执行所需的时间,因此需从Cloudwatch Logs的输出中进行确认。
数据生成(OLAP)
生成SQL语句的数据
- PostgreSQLのgenerate_series関数を利用して、数千万行以上の大量データを生成する。
INSERT INTO sales_order
SELECT
generate_series as order_id, -- 注文ID
timestamp '2014-04-01 00:00:00' + random() * (timestamp '2020-04-01 00:00:00' - timestamp '2014-04-01 00:00:00'), -- 日時
trunc(random() * 100), -- 店舗ID
trunc(random() * 100000000), -- 顧客ID
trunc(random() * 10000) * 10 -- 合計金額
FROM
generate_series(1,50000000); -- データ生成件数を指定 ☆
sales=> select * from sales_order limit 5;
order_id | timestamp | store_id | customer_id | total_price
----------+----------------------------+----------+-------------+-------------
4012545 | 2017-12-11 02:22:17.412715 | 66 | 11732886 | 88080
4012546 | 2014-11-23 10:27:58.553224 | 79 | 39502508 | 17440
4012547 | 2019-09-12 15:34:49.932418 | 56 | 5110535 | 85080
4012548 | 2016-05-13 19:18:07.550354 | 86 | 44695746 | 58170
4012549 | 2016-05-10 15:47:55.556803 | 65 | 14394220 | 68390
在生成了5亿条数据的SQL后,使用了Aurora PostgreSQL db.r5.4xlarge实例,大约花费了50分钟。考虑到启动时间和IO费用,仅Aurora的费用就超过了500日元。
数据迁移
由于在Redshift中无法使用generate_series函数,因此本次将通过S3将在PostgreSQL中生成的数据迁移至Redshift。具体方法如下:首先,按照官方文档的步骤,使用下面的命令将数据从Aurora PostgreSQL(11或更高版本)导出到S3。
SELECT *
FROM aws_s3.query_export_to_s3(
'select * from sales_order',
aws_commons.create_s3_uri('<bucket_name>', 'sales_order.csv', 'ap-northeast-1'),
options :='format csv');
然后,使用COPY命令将导出的数据加载到Redshift中(参考官方文档中的步骤)。
COPY <table_name> FROM 's3://<bucket_name>/<file_path>'
iam_role 'arn:aws:iam::<aws-account-id>:role/<role-name>'
FORMAT csv MAXERROR 10000 COMPUPDATE ON;
由于导出的CSV数据文件中存在损坏的数据行,因此使用MAXERROR子句指定了允许的损坏数据行数量进行了加载(在性能验证中,少量行的差异被认为是误差范围内可接受的)。导出的CSV数据文件大小约为50亿行,大约25GB,将其加载到Redshift花费了约15分钟的时间。
OLAP执行计划
PostgreSQL 形同一种数据库管理系统。
- 10,000万件, 索引なし, 並列度7の条件
sales=> EXPLAIN ANALYZE SELECT store_id, date_trunc('month', timestamp) as month, SUM(total_price) as sales_by_month FROM sales_order_100m GROUP BY store_id, month ORDER BY store_id, month;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
Finalize GroupAggregate (cost=2793263.25..17409493.29 rows=100000120 width=20) (actual time=35255.091..37910.722 rows=7200 loops=1)
Group Key: store_id, (date_trunc('month'::text, "timestamp"))
-> Gather Merge (cost=2793263.25..15409490.89 rows=100000120 width=20) (actual time=35254.343..37904.037 rows=57600 loops=1)
Workers Planned: 8
Workers Launched: 7
-> Partial GroupAggregate (cost=2792263.11..3073513.45 rows=12500015 width=20) (actual time=35209.875..37738.059 rows=7200 loops=8)
Group Key: store_id, (date_trunc('month'::text, "timestamp"))
-> Sort (cost=2792263.11..2823513.15 rows=12500015 width=16) (actual time=35209.404..36555.793 rows=12500000 loops=8)
Sort Key: store_id, (date_trunc('month'::text, "timestamp"))
Sort Method: external merge Disk: 367000kB
Worker 0: Sort Method: external merge Disk: 368024kB
Worker 1: Sort Method: external merge Disk: 367000kB
Worker 2: Sort Method: external merge Disk: 365976kB
Worker 3: Sort Method: external merge Disk: 368016kB
Worker 4: Sort Method: external merge Disk: 365976kB
Worker 5: Sort Method: external merge Disk: 367000kB
Worker 6: Sort Method: external merge Disk: 367000kB
-> Parallel Seq Scan on sales_order_100m (cost=0.00..891545.19 rows=12500015 width=16) (actual time=0.008..2387.244 rows=12500000 loops=8)
Planning Time: 0.091 ms
Execution Time: 37952.773 ms
並列全表掃描(Parallel Seq Scan)正在使用7個工作進程(並列度7)進行執行。
- 5,000万件, 索引あり, 並列度1の条件
sales=> EXPLAIN ANALYZE SELECT store_id, date_trunc('month', timestamp) as month, SUM(total_price) as sales_by_month FROM sales_order_50m GROUP BY store_id, month;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
GroupAggregate (cost=0.56..4337021.90 rows=50000000 width=20) (actual time=7.162..48230.888 rows=7200 loops=1)
Group Key: store_id, date_trunc('month'::text, "timestamp")
-> Index Scan using sales_order_50m_idx_01 on sales_order_50m (cost=0.56..3337021.90 rows=50000000 width=16) (actual time=0.027..43732.779 rows=50000000 loops=1)
Planning Time: 0.136 ms
Execution Time: 48235.022 ms
(5 行)
正在执行直列索引扫描。工作器未被启动/执行。
红移
- 10,000万行の条件
sales=# SELECT plannode || ' ' || info FROM stl_explain WHERE query = 677 ORDER BY nodeid;
?column?
----------------------------------------------------------------------------------------
XN HashAggregate (cost=1999991.84..2488343.60 rows=97670353 width=16)
-> XN Seq Scan on sales_order_100m (cost=0.00..1249994.90 rows=99999592 width=16)
(2 行)
根据排序键是否存在,执行计划没有发生变化。
AWS官网将DynamoDB分类为KVS和文档型数据库,而不是宽列存储。但是考虑到Cassandra作为一种代表性的宽列存储是基于DynamoDB的论文创建的,并且Cassandra和DynamoDB在数据存储方式和性能特性上有相似之处,个人认为也可以将其看作是一种宽列存储。
对于业务系统和分析系统,业务系统是指用于业务自动化/效率化的系统(例如订单销售系统和生产管理系统),而分析系统是指用于可视化/分析数据以获得洞察的系统(例如销售总结系统和财务分析系统)。
由于Aurora PostgreSQL 11.6 db.r5.4xlarge(16个vCPU,128 GiB)的性能过高,因此从比较图中将其排除。值得一提的是,与Aurora Serverless PostgreSQL 10.7(ACU 2)相比,它的吞吐量提高了约2.5倍至3.0倍。
由于DynamoDB不支持聚合查询(GROUP BY子句),而Aurora Servreless由于自动扩展功能导致无法测量稳定的性能,因此将它们从比较对象中排除。
在官方文档中提到,每个ACU是处理能力和内存容量的组合。
当将负载从Lambda更改为EC2并进行检查时,使用Aurora Data API并行度为10-15时,CPU利用率达到90-100%,而使用psycopg2时,CPU利用率低于10%。是HTTPS通信中加密处理导致的CPU负载吗?
官方文档中的解释是,一个写入吞吐量单位(WCU)表示每秒钟对最大大小为1 KB的项执行一次写入。
请注意OLTP图的并行度(查询本身的同时执行数)和OLAP图的并行度(一个查询内的CPU进程并行执行数)的含义差异。