OceanBase學習之路15|體驗 Operational OLAP
OceanBase 資料庫可以處理混合負載型別的場景。由於 OceanBase 資料庫是基於對等節點的分散式架構,使得它既可以承載高併發和可擴充套件的 OLTP 任務,還可以在同一套資料引擎中基於 MPP 架構進行 OLAP 的平行計算,無需維護兩套資料。
在 OceanBase 資料庫中,您不但可以在大量線上業務資料上直接進行並行分析,還可以透過 PDML 能力(Parallel DML)將批次寫入資料的大事務以併發的方式快速安全的執行。並且,這一切都是在嚴格保證事務一致性的前提下做到的。
下面讓我們手動進行 TPC-H 測試,演示 OceanBase 資料庫在 Operational OLAP 場景的特點和用法。TPC-H 是一個業界常用的基於決策支援業務的 Benchmark,透過一系列在大量資料集上面執行的複雜查詢請求,檢驗資料庫系統的分析以及決策支援能力。詳細相信可參見 TPC 組織官方網站。(2021年5月20日,OceanBase 資料庫以 1526 萬 QphH 的成績重新整理了 TPC-H 世界紀錄,並且是唯一一個同時重新整理了TPC-C 以及 TPC-H 紀錄的資料庫,證明瞭其能夠同時處理線上交易和實時分析兩類業務場景能力。詳細資訊請參見 )
手動進行 TPC-H 測試
以下內容為基於 TPC 官方 TPC-H 工具進行手動 Step-by-Step 進行 TPC-H 測試。手動測試可以幫助更好的學習和了解 OceanBase 資料庫,尤其是一些引數的設定。
進行環境調優
請在系統租戶
sys
下進行環境調優。
-
OceanBase 資料庫調優。 在系統租戶下執行
obclient -h$host_ip -P$host_port -uroot@sys -A
命令。alter system set enable_sql_audit=False; alter system set enable_sql_extension=True tenant=<your tenant name>; alter system set syslog_level='PERF'; alter system set max_syslog_file_count=100; alter system set trace_log_slow_query_watermark='100s'; alter system set _hash_area_size='3g' tenant=<your tenant name>; alter system set enable_rebalance=False; alter system set memory_chunk_cache_size=0; alter system set cache_wash_threshold='30g'; alter system set ob_enable_batched_multi_statement=True tenant=<your tenant name>"; alter system set _bloom_filter_ratio=10; alter system set _rowsets_enabled=True tenant=<your tenant name>"; alter system set _parallel_server_sleep_time=10; alter system set cpu_quota_concurrency=4; alter system set syslog_io_bandwidth_limit='30m'; alter system set enable_async_syslog=True; alter system set large_query_worker_percentage=10; alter system set builtin_db_data_verify_cycle=0; alter system set micro_block_merge_verify_level=0; alter system set freeze_trigger_percentage=50; alter system set enable_perf_event=False; alter system set large_query_threshold='1s'; # 儲存下壓和向量化設定後,如果非第一次設定,一定要重新整理 plan cache 才生效 alter system flush plan cache global;
-
設定租戶。 在測試使用者下執行
obclient -h$host_ip -P$host_port -u$user@$tenant -p$password -A
命令。set global ob_sql_work_area_percentage = 80; set global optimizer_use_sql_plan_baselines = True; set global optimizer_capture_sql_plan_baselines = True; set global ob_query_timeout = 36000000000; set global ob_trx_timeout = 36000000000; set global max_allowed_packet = 67108864; # parallel_servers_target = max_cpu * server_num * 8 set global parallel_servers_target = 624; set global _groupby_nopushdown_cut_ratio = 1; # 由於安全原因,只能使用observer本地client變更secure_file_priv set global secure_file_priv = '';
-
調優引數設定完畢後請執行 obd cluster restart $cluster_name 命令重啟叢集。
安裝 TPC-H Tool
-
下載 TPC-H Tool。詳細資訊請參考 TPC-H Tool 下載頁面。
-
下載完成後解壓檔案,進入 TPC-H 解壓後的目錄。
[wieck@localhost ~] $ unzip 7e965ead-8844-4efa-a275-34e35f8ab89b-tpc-h-tool.zip [wieck@localhost ~] $ cd TPC-H_Tools_v3.0.0
-
複製
Makefile.suite
。[wieck@localhost TPC-H_Tools_v3.0.0] $ cd dbgen/ [wieck@localhost dbgen] $ cp Makefile.suite Makefile
-
修改
Makefile
檔案中的 CC、DATABASE、MACHINE、WORKLOAD 等引數定義。[wieck@localhost dbgen] $ vim Makefile CC = gcc # Current values for DATABASE are: INFORMIX, DB2, TDAT (Teradata) # SQLSERVER, SYBASE, ORACLE, VECTORWISE # Current values for MACHINE are: ATT, DOS, HP, IBM, ICL, MVS, # SGI, SUN, U2200, VMS, LINUX, WIN32 # Current values for WORKLOAD are: TPCH DATABASE= MYSQL MACHINE = LINUX WORKLOAD = TPCH
-
修改
tpcd.h
檔案,並新增新的宏定義。[wieck@localhost dbgen] $ vim tpcd.h #ifdef MYSQL #define GEN_QUERY_PLAN "" #define START_TRAN "START TRANSACTION" #define END_TRAN "COMMIT" #define SET_OUTPUT "" #define SET_ROWCOUNT "limit %d;\n" #define SET_DBASE "use %s;\n" #endif
6.編譯檔案。
make
生成資料
您可以根據實際環境生成 TCP-H 10G、100G 或者 1T 資料。本文以生成 100G 資料為例。
./dbgen -s 100 mkdir tpch100 mv *.tbl tpch100
生成查詢 SQL
說明
您可參考本節中的下述步驟生成查詢 SQL 後進行調整,也可直接使用 中給出的查詢 SQL。
若您選擇使用 GitHub 中的查詢 SQL,您需將 SQL 語句中的
cpu_num
修改為實際併發數。
-
複製
qgen
和dists.dss
檔案至queries
目錄。cp qgen queries cp dists.dss queries
-
在
queries
目錄下建立gen.sh
指令碼生成查詢 SQL。[wieck@localhost queries] $ vim gen.sh #!/usr/bin/bash for i in {1..22} do ./qgen -d $i -s 100 > db"$i".sql done
-
執行
gen.sh
指令碼。chmod +x gen.sh ./gen.sh
-
查詢 SQL 進行調整。
dos2unix *
調整後的查詢 SQL 請參考
。您需將 GitHub 給出的 SQL 語句中的
cpu_num
修改為實際併發數。建議併發數的數值與可用 CPU 總數相同,兩者相等時效能最好。
您可在
sys
租戶下使用如下命令檢視租戶的可用 CPU 總數。
select sum(cpu_capacity_max) from __all_virtual_server;
以
q1
為例,修改後的 SQL 語句如下:
select /*+ parallel(96) */ ---增加 parallel 併發執行 l_returnflag, l_linestatus, sum(l_quantity) as sum_qty, sum(l_extendedprice) as sum_base_price, sum(l_extendedprice * (1 - l_discount)) as sum_disc_price, sum(l_extendedprice * (1 - l_discount) * (1 + l_tax)) as sum_charge, avg(l_quantity) as avg_qty, avg(l_extendedprice) as avg_price, avg(l_discount) as avg_disc, count(*) as count_order from lineitem where l_shipdate <= date '1998-12-01' - interval '90' day group by l_returnflag, l_linestatus order by l_returnflag, l_linestatus;
新建表
建立表結構檔案
create_tpch_mysql_table_part.ddl
。
drop table if exists lineitem; drop table if exists orders; drop table if exists partsupp; drop table if exists part; drop table if exists customer; drop table if exists supplier; drop table if exists nation; drop table if exists region; drop tablegroup if exists tpch_tg_lineitem_order_group; drop tablegroup if exists tpch_tg_partsupp_part; create tablegroup if not exists tpch_tg_lineitem_order_group binding true partition by key 1 partitions cpu_num; create tablegroup if not exists tpch_tg_partsupp_part binding true partition by key 1 partitions cpu_num; drop table if exists lineitem; create table lineitem ( l_orderkey BIGINT NOT NULL, l_partkey BIGINT NOT NULL, l_suppkey INTEGER NOT NULL, l_linenumber INTEGER NOT NULL, l_quantity DECIMAL(15,2) NOT NULL, l_extendedprice DECIMAL(15,2) NOT NULL, l_discount DECIMAL(15,2) NOT NULL, l_tax DECIMAL(15,2) NOT NULL, l_returnflag char(1) DEFAULT NULL, l_linestatus char(1) DEFAULT NULL, l_shipdate date NOT NULL, l_commitdate date DEFAULT NULL, l_receiptdate date DEFAULT NULL, l_shipinstruct char(25) DEFAULT NULL, l_shipmode char(10) DEFAULT NULL, l_comment varchar(44) DEFAULT NULL, primary key(l_orderkey, l_linenumber))row_format = condensed tablegroup = tpch_tg_lineitem_order_group partition by key (l_orderkey) partitions cpu_num; drop table if exists orders; create table orders ( o_orderkey bigint not null, o_custkey bigint not null, o_orderstatus char(1) default null, o_totalprice bigint default null, o_orderdate date not null, o_orderpriority char(15) default null, o_clerk char(15) default null, o_shippriority bigint default null, o_comment varchar(79) default null, primary key (o_orderkey))row_format = condensed tablegroup = tpch_tg_lineitem_order_group partition by key(o_orderkey) partitions cpu_num; drop table if exists partsupp; create table partsupp ( ps_partkey bigint not null, ps_suppkey bigint not null, ps_availqty bigint default null, ps_supplycost bigint default null, ps_comment varchar(199) default null, primary key (ps_partkey, ps_suppkey))row_format = condensed tablegroup tpch_tg_partsupp_part partition by key(ps_partkey) partitions cpu_num; drop table if exists part; create table part ( p_partkey bigint not null, p_name varchar(55) default null, p_mfgr char(25) default null, p_brand char(10) default null, p_type varchar(25) default null, p_size bigint default null, p_container char(10) default null, p_retailprice bigint default null, p_comment varchar(23) default null, primary key (p_partkey))row_format = condensed tablegroup tpch_tg_partsupp_part partition by key(p_partkey) partitions cpu_num; drop table if exists customer; create table customer ( c_custkey bigint not null, c_name varchar(25) default null, c_address varchar(40) default null, c_nationkey bigint default null, c_phone char(15) default null, c_acctbal bigint default null, c_mktsegment char(10) default null, c_comment varchar(117) default null, primary key (c_custkey))row_format = condensed partition by key(c_custkey) partitions cpu_num; drop table if exists supplier; create table supplier ( s_suppkey bigint not null, s_name char(25) default null, s_address varchar(40) default null, s_nationkey bigint default null, s_phone char(15) default null, s_acctbal bigint default null, s_comment varchar(101) default null, primary key (s_suppkey))row_format = condensed partition by key(s_suppkey) partitions cpu_num; drop table if exists nation; create table nation ( n_nationkey bigint not null, n_name char(25) default null, n_regionkey bigint default null, n_comment varchar(152) default null, primary key (n_nationkey))row_format = condensed; drop table if exists region; create table region ( r_regionkey bigint not null, r_name char(25) default null, r_comment varchar(152) default null, primary key (r_regionkey))row_format = condensed;
載入資料
您可以根據上述步驟生成的資料和 SQL 自行編寫指令碼。載入資料示例操作如下:
-
建立載入指令碼目錄。
[wieck@localhost dbgen] $ mkdir load [wieck@localhost dbgen] $ cd load [wieck@localhost load] $ cp ../dss.ri ../dss.ddl ./
-
建立
load.py
指令碼。[wieck@localhost load] $ vim load.py #!/usr/bin/env python #-*- encoding:utf-8 -*- import os import sys import time import commands hostname='$host_ip' # 注意!!請填寫某個 observer,如 observer A 所在伺服器的 IP 地址 port='$host_port' # observer A 的埠號 tenant='$tenant_name' # 租戶名 user='$user' # 使用者名稱 password='$password' # 密碼 data_path='$path' # 注意!!請填寫 observer A 所在伺服器下 tbl 所在目錄 db_name='$db_name' # 資料庫名 # 建立表 cmd_str='obclient -h%s -P%s -u%s@%s -p%s -D%s < create_tpch_mysql_table_part.ddl'%(hostname,port,user,tenant,password,db_name) result = commands.getstatusoutput(cmd_str) print result cmd_str='obclient -h%s -P%s -u%s@%s -p%s -D%s -e "show tables;" '%(hostname,port,user,tenant,password,db_name) result = commands.getstatusoutput(cmd_str) print result cmd_str=""" obclient -h%s -P%s -u%s@%s -p%s -c -D%s -e "load data /*+ parallel(80) */ infile '%s/customer.tbl' into table customer fields terminated by '|';" """ %(hostname,port,user,tenant,password,db_name,data_path) result = commands.getstatusoutput(cmd_str) print result cmd_str=""" obclient -h%s -P%s -u%s@%s -p%s -c -D%s -e "load data /*+ parallel(80) */ infile '%s/lineitem.tbl' into table lineitem fields terminated by '|';" """ %(hostname,port,user,tenant,password,db_name,data_path) result = commands.getstatusoutput(cmd_str) print result cmd_str=""" obclient -h%s -P%s -u%s@%s -p%s -c -D%s -e "load data /*+ parallel(80) */ infile '%s/nation.tbl' into table nation fields terminated by '|';" """ %(hostname,port,user,tenant,password,db_name,data_path) result = commands.getstatusoutput(cmd_str) print result cmd_str=""" obclient -h%s -P%s -u%s@%s -p%s -c -D%s -e "load data /*+ parallel(80) */ infile '%s/orders.tbl' into table orders fields terminated by '|';" """ %(hostname,port,user,tenant,password,db_name,data_path) result = commands.getstatusoutput(cmd_str) print result cmd_str=""" obclient -h%s -P%s -u%s@%s -p%s -D%s -e "load data /*+ parallel(80) */ infile '%s/partsupp.tbl' into table partsupp fields terminated by '|';" """ %(hostname,port,user,tenant,password,db_name,data_path) result = commands.getstatusoutput(cmd_str) print result cmd_str=""" obclient -h%s -P%s -u%s@%s -p%s -c -D%s -e "load data /*+ parallel(80) */ infile '%s/part.tbl' into table part fields terminated by '|';" """ %(hostname,port,user,tenant,password,db_name,data_path) result = commands.getstatusoutput(cmd_str) print result cmd_str=""" obclient -h%s -P%s -u%s@%s -p%s -c -D%s -e "load data /*+ parallel(80) */ infile '%s/region.tbl' into table region fields terminated by '|';" """ %(hostname,port,user,tenant,password,db_name,data_path) result = commands.getstatusoutput(cmd_str) print result cmd_str=""" obclient -h%s -P%s -u%s@%s -p%s -c -D%s -e "load data /*+ parallel(80) */ infile '%s/supplier.tbl' into table supplier fields terminated by '|';" """ %(hostname,port,user,tenant,password,db_name,data_path) result = commands.getstatusoutput(cmd_str) print result
-
載入資料。
注意
載入資料需要安裝 OBClient 客戶端。
$ python load.py (0,'') (0, 'obclient: [Warning] Using a password on the command line interface can be insecure.\nTABLE_NAME\nT1\nLINEITEM\nORDERS\nPARTSUPP\nPART\nCUSTOMER\nSUPPLIER\nNATION\nREGION') (0, 'obclient: [Warning] Using a password on the command line interface can be insecure.') (0, 'obclient: [Warning] Using a password on the command line interface can be insecure.') (0, 'obclient: [Warning] Using a password on the command line interface can be insecure.') (0, 'obclient: [Warning] Using a password on the command line interface can be insecure.') (0, 'obclient: [Warning] Using a password on the command line interface can be insecure.') (0, 'obclient: [Warning] Using a password on the command line interface can be insecure.') (0, 'obclient: [Warning] Using a password on the command line interface can be insecure.')
-
執行合併。
Major 合併將當前大版本的 SSTable 和 MemTable 與前一個大版本的全量靜態資料進行合併,使儲存層統計資訊更準確,生成的執行計劃更穩定。
注意
執行合併需要使用
sys
租戶登入。MySQL [(none)]> use oceanbase Database changed MySQL [oceanbase]> alter system major freeze tenant=<your tenant name>; Query OK, 0 rows affected
-
檢視合併是否完成。
MySQL [oceanbase]> select FROZEN_SCN, LAST_SCN from oceanbase.CDB_OB_MAJOR_COMPACTION; +---------------------+---------------------+ | FROZEN_SCN | LAST_SCN | +---------------------+---------------------+ | 1667239201167716767 | 1667239201167716767 | | 1667239200111919300 | 1667239200111919300 | | 1667239201167452168 | 1667239201167452168 | | 1667239201168053124 | 1667239201168053124 | | 1667239201167520213 | 1667239201167520213 | +---------------------+---------------------+
說明
所有的 FROZEN_SCN 和 LAST_SCN 的值相等即表示合併完成。
-
手動收集統計資訊
在測試使用者下執行
obclient -h$host_ip -P$host_port -u$user@$tenant -p$password -A -D$database
命令。
set _force_parallel_query_dop = 96; analyze table lineitem partition(lineitem) compute statistics for all columns size auto; analyze table orders partition(orders) compute statistics for all columns size auto; analyze table partsupp partition(partsupp) compute statistics for all columns size auto; analyze table part partition(part) compute statistics for all columns size auto; analyze table customer partition(customer) compute statistics for all columns size auto; analyze table supplier partition(supplier) compute statistics for all columns size auto; analyze table nation compute statistics for all columns size auto; analyze table region compute statistics for all columns size auto;
說明
_force_parallel_query_dop
可以設定當前session
上的query
併發度,取值為cpu_num
。
執行測試
您可以根據上述步驟生成的資料和 SQL 自行編寫指令碼。執行測試示例操作如下:
-
在
queries
目錄下編寫測試指令碼tpch.sh
。[wieck@localhost queries] $ vim tpch.sh #!/bin/bash TPCH_TEST="obclient -h $host_ip -P $host_port -utpch_100g_part@tpch_mysql -D tpch_100g_part -ptest -c" # warmup預熱 for i in {1..22} do sql1="source db${i}.sql" echo $sql1| $TPCH_TEST >db${i}.log || ret=1 done # 正式執行 for i in {1..22} do starttime=`date +%s%N` echo `date '+[%Y-%m-%d %H:%M:%S]'` "BEGIN Q${i}" sql1="source db${i}.sql" echo $sql1| $TPCH_TEST >db${i}.log || ret=1 stoptime=`date +%s%N` costtime=`echo $stoptime $starttime | awk '{printf "%0.2f\n", ($1 - $2) / 1000000000}'` echo `date '+[%Y-%m-%d %H:%M:%S]'` "END,COST ${costtime}s" done
-
執行測試指令碼。
sh tpch.sh
FAQ
-
匯入資料失敗。報錯資訊如下:
ERROR 1017 (HY000) at line 1: File not exist
tbl
檔案必須放在所連線的 OceanBase 資料庫所在機器的某個目錄下,因為載入資料必須本地匯入。 -
檢視資料包錯。報錯資訊如下:
ERROR 4624 (HY000):No memory or reach tenant memory limit
記憶體不足,建議增大租戶記憶體。
-
匯入資料包錯。報錯資訊如下:
ERROR 1227 (42501) at line 1: Access denied
需要授予使用者訪問許可權。執行以下命令,授予許可權:
grant file on *.* to tpch_100g_part;
-
查詢 SQL 進行調整 dos2unix * 時報錯,報錯資訊如下:
-bash: dos2unix: command not found
需要安裝 dos2unix。執行以下命令,即可安裝:
yum install -y dos2unix
手動體驗 Operational OLAP
透過上一步的操作,我們已經獲得了一個 TPCH 的測試環境,下面讓我們透過手動執行來看看,OceanBase 資料庫在 OLAP 方面的能力和特性。 我們先使用 OBClient 登入到資料庫中,如果您沒有安裝 OBClient,使用
mysql
客戶端也是可以的。
obclient -h127.0.0.1 -P2881 -uroot@test -Dtest -A -p -c
在開始之前,您需要根據 OceanBase 叢集和租戶的配置,進行並行度的設定,具體大小建議不超過當前租戶配置的 CPU 核數的 2 倍。例如您的租戶 CPU 最大配置為8,那麼此處建議並行度設定為16:
MySQL [test]> SET GLOBAL parallel_servers_target=16; Query OK, 0 rows affected
OceanBase 資料庫相容大多數 MySQL 的內部檢視,我們可以透過如下查詢檢視當前環境中表的大小:
MySQL [test]> SELECT table_name, table_rows, CONCAT(ROUND(data_length/(1024*1024*1024),2),' GB') table_size FROM information_schema.TABLES WHERE table_schema = 'test' order by table_rows desc; +------------+------------+------------+ | table_name | table_rows | table_size | +------------+------------+------------+ | lineitem | 6001215 | 0.37 GB | | orders | 1500000 | 0.08 GB | | partsupp | 800000 | 0.04 GB | | part | 200000 | 0.01 GB | | customer | 150000 | 0.01 GB | | supplier | 10000 | 0.00 GB | | nation | 25 | 0.00 GB | | region | 5 | 0.00 GB | +------------+------------+------------+ 8 rows in set
下面我們透過 TPC-H 測試中的 Q1 來體驗 OceanBase 資料庫查詢能力,Q1 查詢會在最大的
lineitem
表上,彙總分析指定時間內各類商品的價格、折扣、發貨、數量等資訊。這個查詢對全表資料都會進行讀取、並進行分割槽、排序、聚合等計算。
不開啟併發查詢
首先,我們在預設不開啟併發的情況下執行該查詢:
select l_returnflag, l_linestatus, sum(l_quantity) as sum_qty, sum(l_extendedprice) as sum_base_price, sum(l_extendedprice * (1 - l_discount)) as sum_disc_price, sum(l_extendedprice * (1 - l_discount) * (1 + l_tax)) as sum_charge, avg(l_quantity) as avg_qty, avg(l_extendedprice) as avg_price, avg(l_discount) as avg_disc, count(*) as count_order from lineitem where l_shipdate <= date '1998-12-01' - interval '90' day group by l_returnflag, l_linestatus order by l_returnflag, l_linestatus;
在本例的測試環境中,執行結果如下:
+--------------+--------------+----------+----------------+----------------+--------------+---------+------------+----------+-------------+ | l_returnflag | l_linestatus | sum_qty | sum_base_price | sum_disc_price | sum_charge | avg_qty | avg_price | avg_disc | count_order | +--------------+--------------+----------+----------------+----------------+--------------+---------+------------+----------+-------------+ | A | F | 37734107 | 56586577106 | 56586577106 | 56586577106 | 25.5220 | 38273.1451 | 0.0000 | 1478493 | | N | F | 991417 | 1487505208 | 1487505208 | 1487505208 | 25.5165 | 38284.4806 | 0.0000 | 38854 | | N | O | 74476040 | 111701776272 | 111701776272 | 111701776272 | 25.5022 | 38249.1339 | 0.0000 | 2920374 | | R | F | 37719753 | 56568064200 | 56568064200 | 56568064200 | 25.5058 | 38250.8701 | 0.0000 | 1478870 | +--------------+--------------+----------+----------------+----------------+--------------+---------+------------+----------+-------------+ 4 rows in set (6.791 sec)
開啟併發查詢
OceanBase 資料庫的 Operational OLAP 能力基於一套資料以及執行引擎,無需進行異構的資料同步和維護。下面我們透過新增一個
parallel
Hint,以並行度為8的方式再次執行這條語句:
select /*+parallel(8) */ l_returnflag, l_linestatus, sum(l_quantity) as sum_qty, sum(l_extendedprice) as sum_base_price, sum(l_extendedprice * (1 - l_discount)) as sum_disc_price, sum(l_extendedprice * (1 - l_discount) * (1 + l_tax)) as sum_charge, avg(l_quantity) as avg_qty, avg(l_extendedprice) as avg_price, avg(l_discount) as avg_disc, count(*) as count_order from lineitem where l_shipdate <= date '1998-12-01' - interval '90' day group by l_returnflag, l_linestatus order by l_returnflag, l_linestatus;
在相同的環境和資料集中,執行結果如下:
+--------------+--------------+----------+----------------+----------------+--------------+---------+------------+----------+-------------+ | l_returnflag | l_linestatus | sum_qty | sum_base_price | sum_disc_price | sum_charge | avg_qty | avg_price | avg_disc | count_order | +--------------+--------------+----------+----------------+----------------+--------------+---------+------------+----------+-------------+ | A | F | 37734107 | 56586577106 | 56586577106 | 56586577106 | 25.5220 | 38273.1451 | 0.0000 | 1478493 | | N | F | 991417 | 1487505208 | 1487505208 | 1487505208 | 25.5165 | 38284.4806 | 0.0000 | 38854 | | N | O | 74476040 | 111701776272 | 111701776272 | 111701776272 | 25.5022 | 38249.1339 | 0.0000 | 2920374 | | R | F | 37719753 | 56568064200 | 56568064200 | 56568064200 | 25.5058 | 38250.8701 | 0.0000 | 1478870 | +--------------+--------------+----------+----------------+----------------+--------------+---------+------------+----------+-------------+ 4 rows in set (1.197 sec)
可以看到,對比預設無併發的執行耗時,並行查詢下速度提升了將近 6 倍。如果我們透過
EXPLAIN
命令檢視執行計劃,也可以看到並行度的展示(第 18 行,1 號運算元,dop=8):
=============================================================== |ID|OPERATOR |NAME |EST. ROWS|COST | --------------------------------------------------------------- |0 |PX COORDINATOR MERGE SORT | |6 |13507125| |1 | EXCHANGE OUT DISTR |:EX10001|6 |13507124| |2 | SORT | |6 |13507124| |3 | HASH GROUP BY | |6 |13507107| |4 | EXCHANGE IN DISTR | |6 |8379337 | |5 | EXCHANGE OUT DISTR (HASH)|:EX10000|6 |8379335 | |6 | HASH GROUP BY | |6 |8379335 | |7 | PX BLOCK ITERATOR | |5939712 |3251565 | |8 | TABLE SCAN |lineitem|5939712 |3251565 | =============================================================== Outputs & filters: ------------------------------------- 0 - output([lineitem.l_returnflag], [lineitem.l_linestatus], [T_FUN_SUM(T_FUN_SUM(lineitem.l_quantity))], [T_FUN_SUM(T_FUN_SUM(lineitem.l_extendedprice))], [T_FUN_SUM(T_FUN_SUM(lineitem.l_extendedprice * 1 - lineitem.l_discount))], [T_FUN_SUM(T_FUN_SUM(lineitem.l_extendedprice * 1 - lineitem.l_discount * 1 + lineitem.l_tax))], [T_FUN_SUM(T_FUN_SUM(lineitem.l_quantity)) / cast(T_FUN_COUNT_SUM(T_FUN_COUNT(lineitem.l_quantity)), DECIMAL(20, 0))], [T_FUN_SUM(T_FUN_SUM(lineitem.l_extendedprice)) / cast(T_FUN_COUNT_SUM(T_FUN_COUNT(lineitem.l_extendedprice)), DECIMAL(20, 0))], [T_FUN_SUM(T_FUN_SUM(lineitem.l_discount)) / cast(T_FUN_COUNT_SUM(T_FUN_COUNT(lineitem.l_discount)), DECIMAL(20, 0))], [T_FUN_COUNT_SUM(T_FUN_COUNT(*))]), filter(nil), sort_keys([lineitem.l_returnflag, ASC], [lineitem.l_linestatus, ASC]) 1 - output([lineitem.l_returnflag], [lineitem.l_linestatus], [T_FUN_SUM(T_FUN_SUM(lineitem.l_quantity))], [T_FUN_SUM(T_FUN_SUM(lineitem.l_extendedprice))], [T_FUN_SUM(T_FUN_SUM(lineitem.l_extendedprice * 1 - lineitem.l_discount))], [T_FUN_SUM(T_FUN_SUM(lineitem.l_extendedprice * 1 - lineitem.l_discount * 1 + lineitem.l_tax))], [T_FUN_COUNT_SUM(T_FUN_COUNT(*))], [T_FUN_SUM(T_FUN_SUM(lineitem.l_quantity)) / cast(T_FUN_COUNT_SUM(T_FUN_COUNT(lineitem.l_quantity)), DECIMAL(20, 0))], [T_FUN_SUM(T_FUN_SUM(lineitem.l_extendedprice)) / cast(T_FUN_COUNT_SUM(T_FUN_COUNT(lineitem.l_extendedprice)), DECIMAL(20, 0))], [T_FUN_SUM(T_FUN_SUM(lineitem.l_discount)) / cast(T_FUN_COUNT_SUM(T_FUN_COUNT(lineitem.l_discount)), DECIMAL(20, 0))]), filter(nil), dop=8 2 - output([lineitem.l_returnflag], [lineitem.l_linestatus], [T_FUN_SUM(T_FUN_SUM(lineitem.l_quantity))], [T_FUN_SUM(T_FUN_SUM(lineitem.l_extendedprice))], [T_FUN_SUM(T_FUN_SUM(lineitem.l_extendedprice * 1 - lineitem.l_discount))], [T_FUN_SUM(T_FUN_SUM(lineitem.l_extendedprice * 1 - lineitem.l_discount * 1 + lineitem.l_tax))], [T_FUN_COUNT_SUM(T_FUN_COUNT(*))], [T_FUN_SUM(T_FUN_SUM(lineitem.l_quantity)) / cast(T_FUN_COUNT_SUM(T_FUN_COUNT(lineitem.l_quantity)), DECIMAL(20, 0))], [T_FUN_SUM(T_FUN_SUM(lineitem.l_extendedprice)) / cast(T_FUN_COUNT_SUM(T_FUN_COUNT(lineitem.l_extendedprice)), DECIMAL(20, 0))], [T_FUN_SUM(T_FUN_SUM(lineitem.l_discount)) / cast(T_FUN_COUNT_SUM(T_FUN_COUNT(lineitem.l_discount)), DECIMAL(20, 0))]), filter(nil), sort_keys([lineitem.l_returnflag, ASC], [lineitem.l_linestatus, ASC]) 3 - output([lineitem.l_returnflag], [lineitem.l_linestatus], [T_FUN_SUM(T_FUN_SUM(lineitem.l_quantity))], [T_FUN_SUM(T_FUN_SUM(lineitem.l_extendedprice))], [T_FUN_SUM(T_FUN_SUM(lineitem.l_extendedprice * 1 - lineitem.l_discount))], [T_FUN_SUM(T_FUN_SUM(lineitem.l_extendedprice * 1 - lineitem.l_discount * 1 + lineitem.l_tax))], [T_FUN_COUNT_SUM(T_FUN_COUNT(lineitem.l_quantity))], [T_FUN_COUNT_SUM(T_FUN_COUNT(lineitem.l_extendedprice))], [T_FUN_SUM(T_FUN_SUM(lineitem.l_discount))], [T_FUN_COUNT_SUM(T_FUN_COUNT(lineitem.l_discount))], [T_FUN_COUNT_SUM(T_FUN_COUNT(*))]), filter(nil), group([lineitem.l_returnflag], [lineitem.l_linestatus]), agg_func([T_FUN_SUM(T_FUN_SUM(lineitem.l_quantity))], [T_FUN_SUM(T_FUN_SUM(lineitem.l_extendedprice))], [T_FUN_SUM(T_FUN_SUM(lineitem.l_extendedprice * 1 - lineitem.l_discount))], [T_FUN_SUM(T_FUN_SUM(lineitem.l_extendedprice * 1 - lineitem.l_discount * 1 + lineitem.l_tax))], [T_FUN_COUNT_SUM(T_FUN_COUNT(*))], [T_FUN_COUNT_SUM(T_FUN_COUNT(lineitem.l_quantity))], [T_FUN_COUNT_SUM(T_FUN_COUNT(lineitem.l_extendedprice))], [T_FUN_SUM(T_FUN_SUM(lineitem.l_discount))], [T_FUN_COUNT_SUM(T_FUN_COUNT(lineitem.l_discount))]) 4 - output([lineitem.l_returnflag], [lineitem.l_linestatus], [T_FUN_SUM(lineitem.l_quantity)], [T_FUN_SUM(lineitem.l_extendedprice)], [T_FUN_SUM(lineitem.l_extendedprice * 1 - lineitem.l_discount)], [T_FUN_SUM(lineitem.l_extendedprice * 1 - lineitem.l_discount * 1 + lineitem.l_tax)], [T_FUN_COUNT(lineitem.l_quantity)], [T_FUN_COUNT(lineitem.l_extendedprice)], [T_FUN_SUM(lineitem.l_discount)], [T_FUN_COUNT(lineitem.l_discount)], [T_FUN_COUNT(*)]), filter(nil) 5 - (#keys=2, [lineitem.l_returnflag], [lineitem.l_linestatus]), output([lineitem.l_returnflag], [lineitem.l_linestatus], [T_FUN_SUM(lineitem.l_quantity)], [T_FUN_SUM(lineitem.l_extendedprice)], [T_FUN_SUM(lineitem.l_extendedprice * 1 - lineitem.l_discount)], [T_FUN_SUM(lineitem.l_extendedprice * 1 - lineitem.l_discount * 1 + lineitem.l_tax)], [T_FUN_COUNT(lineitem.l_quantity)], [T_FUN_COUNT(lineitem.l_extendedprice)], [T_FUN_SUM(lineitem.l_discount)], [T_FUN_COUNT(lineitem.l_discount)], [T_FUN_COUNT(*)]), filter(nil), dop=8 6 - output([lineitem.l_returnflag], [lineitem.l_linestatus], [T_FUN_SUM(lineitem.l_quantity)], [T_FUN_SUM(lineitem.l_extendedprice)], [T_FUN_SUM(lineitem.l_extendedprice * 1 - lineitem.l_discount)], [T_FUN_SUM(lineitem.l_extendedprice * 1 - lineitem.l_discount * 1 + lineitem.l_tax)], [T_FUN_COUNT(lineitem.l_quantity)], [T_FUN_COUNT(lineitem.l_extendedprice)], [T_FUN_SUM(lineitem.l_discount)], [T_FUN_COUNT(lineitem.l_discount)], [T_FUN_COUNT(*)]), filter(nil), group([lineitem.l_returnflag], [lineitem.l_linestatus]), agg_func([T_FUN_SUM(lineitem.l_quantity)], [T_FUN_SUM(lineitem.l_extendedprice)], [T_FUN_SUM(lineitem.l_extendedprice * 1 - lineitem.l_discount)], [T_FUN_SUM(lineitem.l_extendedprice * 1 - lineitem.l_discount * 1 + lineitem.l_tax)], [T_FUN_COUNT(*)], [T_FUN_COUNT(lineitem.l_quantity)], [T_FUN_COUNT(lineitem.l_extendedprice)], [T_FUN_SUM(lineitem.l_discount)], [T_FUN_COUNT(lineitem.l_discount)]) 7 - output([lineitem.l_returnflag], [lineitem.l_linestatus], [lineitem.l_quantity], [lineitem.l_extendedprice], [lineitem.l_discount], [lineitem.l_extendedprice * 1 - lineitem.l_discount], [lineitem.l_extendedprice * 1 - lineitem.l_discount * 1 + lineitem.l_tax]), filter(nil) 8 - output([lineitem.l_returnflag], [lineitem.l_linestatus], [lineitem.l_quantity], [lineitem.l_extendedprice], [lineitem.l_discount], [lineitem.l_extendedprice * 1 - lineitem.l_discount], [lineitem.l_extendedprice * 1 - lineitem.l_discount * 1 + lineitem.l_tax]), filter([lineitem.l_shipdate <= ?]), access([lineitem.l_shipdate], [lineitem.l_returnflag], [lineitem.l_linestatus], [lineitem.l_quantity], [lineitem.l_extendedprice], [lineitem.l_discount], [lineitem.l_tax]), partitions(p[0-15])
本文中的例子使用單節點環境部署,值得特別說明的是,OceanBase 資料庫的並行執行框架最大的特點是還可以將大量資料的分析查詢以多節點併發執行的方式進行分析,例如一張表包含上億行資料,分佈在多個 OceanBase 資料庫節點上,當進行分析查詢時,OceanBase 資料庫的分散式執行框架可以生成一個分散式並行執行計劃,利用多個節點的資源進行分析,因此具備很好的擴充套件性,同時針對並行的設定還可以在 SQL、會話、表上多個維度進行設定。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70026075/viewspace-2932349/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- OceanBase學習之路13|體驗多租戶特性
- OceanBase學習之路11|體驗 DDL 新特性(Oracle 模式)Oracle模式
- OceanBase學習之路12|體驗 DDL 新特性(MySQL 模式)MySql模式
- OceanBase學習之路16|體驗 OceanBase 資料庫熱點行更新能力資料庫
- OceanBase學習之路14|體驗並行匯入 & 資料壓縮並行
- OceanBase學習之路6|透過 Obclient 連線 OceanBase 租戶client
- OceanBase學習之路3 |SpringJDBC 連線示例SpringJDBC
- OceanBase學習之路4|SpringBoot 連線示例Spring Boot
- OceanBase學習之路9|連線方式概述
- OceanBase學習之路5|C 應用程式連線 OceanBase 資料庫資料庫
- OceanBase學習之路8|Java 應用程式連線 OceanBase 資料庫Java資料庫
- 實踐練習一:OceanBase Docker 體驗Docker
- OceanBase學習之路38|如何合併資源池?
- OceanBase學習之路10|C 相關 API 介紹API
- OceanBase學習之路47|什麼是資源管理?
- OceanBase學習之路54|如何配置多租戶管理?
- OceanBase學習之路7|透過 MySQL 客戶端連線 OceanBase 租戶MySql客戶端
- OceanBase學習之路37|什麼是分裂資源池?
- OceanBase學習之路39|什麼是修改資源池?
- Python學習之路15-下載資料Python
- OceanBase學習之路45|如何檢視資源單元配置?
- OceanBase學習之路48|最佳效能引數的配置參考
- OceanBase學習之路40|如何將資源池分配給租戶?
- OceanBase學習之路42|建立新的資源池的步驟?
- OceanBase學習之路49|最小資源引數配置是什麼?
- OceanBase學習之路53|多租戶管理引數如何設定?
- Android開發學習之路--React-Native混合開發初體驗AndroidReact
- OceanBase學習之路43|如何刪除不再使用的資源單元?
- OceanBase學習之路44|修改資源單元配置有什麼方法??
- FastAPI 學習之路(二十七)安全校驗ASTAPI
- OceanBase學習之路41|如何檢視資源池的分佈情況?
- OceanBase學習之路52|如何透過系統變數進行設定?變數
- Django學習筆記(15)——中介軟體Django筆記
- golang 學習之路之 struct 結構體GolangStruct結構體
- 深度學習--Tensorflow初體驗深度學習
- OceanBase學習之路46|如何透過 SQL 語句或 OCP 建立資源單元?SQL
- OceanBase學習之路50|預設生產引數的建議配置是什麼?
- 4.0體驗站|我對OceanBase 4.0社群版的體驗與看法