更高效能表現、更低資源佔用,高精度計算資料型別 DecimalV3 揭祕
數值運算是資料庫中十分常見的需求,例如計算數量、重量、價格等,為了適應多樣化運算場景,資料庫系統通常支援精準的數字型別和近似的數字型別,當我們需要精確地表示小數並計算小數時,通常會考慮使用 Decimal 資料型別。區別於浮點小數,Decimal 作為定點小數型別,可以支援高精度的小數運算,因此適用於各種高精度計算的場景,常見的應用場景有以下幾種:
- 金融行業:在金融交易中經常涉及到小數,比如利息、金額的計算,金融場景對數字準確的要求極高,因此精確的小數運算是必要的。
- 財務軟體:財務軟體通常需要進行復雜的財務計算,Decimal 型別可以提供精確的小數計算,避免計算過程中產生的舍入誤差。
- 科學計算、工程計算等其他場景。
DecimalV3 功能介紹
在 Apache Doris 1.2.1 之前的版本中,我們已對 Decimal(precision, scale)(precision<=27) 資料型別進行了支援,隨著 Apache Doris 使用者的持續增長,銀行、證券、基金等金融領域的使用者也隨之快速增長,對高精度的小數計算場景也提出了更高的要求,舊的 Decimal 資料型別已無法滿足。因此,我們在 Apache Doris 1.2.1 推出了精度更高、速度更快的 DecimalV3(precision, scale)(precision<=38),實現了真正意義上的高精度定點數,相比於老版本中的 Decimal ,DecimalV3 有以下核心優勢:
- 可表示範圍更大。DECIMALV3 對 Precision 和 Scale 的取值範圍進行擴充。
- 記憶體佔用更低,效能更高。老版本的 Decimal 需要佔用 16 Bytes 的記憶體,而 DecimalV3 對記憶體可進行自適應調整,如下所示。
+----------------------+-------------------+
| precision | 佔用空間(記憶體/磁碟)|
+----------------------+-------------------+
| 0 < precision <= 8 | 4 bytes |
+----------------------+-------------------+
| 8 < precision <= 18 | 8 bytes |
+----------------------+-------------------+
| 18 < precision <= 38 | 16 bytes |
+----------------------+-------------------+
- 更完備的精度推演。
精度推演規則
DECIMALV3 有一套很複雜的型別推演規則,針對不同的表示式,會應用不同規則進行精度推演,下面來介紹一下推演規則:
- 四則運算
- 加法 / 減法:DECIMALV3(a, b) + DECIMALV3(x, y) -> DECIMALV3(max(a - b, x - y) + max(b, y), max(b, y)),即整數部分和小數部分都分別使用兩個運算元中較大的值。
- 乘法:DECIMALV3(a, b) * DECIMALV3(x, y) -> DECIMALV3(a + x, b + y)
- 除法:DECIMALV3(a, b) / DECIMALV3(x, y) -> DECIMALV3(a + y, b)
- 聚合運算
- SUM / MULTI_DISTINCT_SUM:SUM(DECIMALV3(a, b)) -> DECIMALV3(38, b)。
- AVG:AVG(DECIMALV3(a, b)) -> DECIMALV3(38, max(b, 4))(鑑於每個系統 AVG 的精度不同,且不同使用者對精度的需求也不一樣,經調研,決定選擇與 SQLServer 相同的策略,因此選擇“4”既能保證較好的效能,也不會有較大的精度損失。)
- 預設規則
除上述提到的函式外,其餘表示式都使用預設規則進行精度推演。即對於表示式 expr(DECIMALV3(a, b))
,結果型別同樣也是 DECIMALV3(a, b)。
結果精度調整
上述幾種規則為當前 Doris 的預設行為,而不同場景對 DECIMALV3 的精度要求各不相同,遠超出以上幾種規則。當用戶有不同的精度需求,可以通過以下方式進行精度調整:
- 當期望的結果精度大於預設精度時,可通過調整入參精度來調整結果精度。例如使用者期望計算
AVG(col)
得到DECIMALV3(x, y)作為結果,其中col
的型別為 DECIMALV3(a, b),則可以改寫表示式為AVG(CAST(col as DECIMALV3(x, y)))
。 - 當期望的結果精度小於預設精度時,可通過對輸出結果求近似得到想要的精度。例如使用者期望計算
AVG(col)
得到DECIMALV3(x, y)作為結果,其中col
的型別為DECIMALV3(a, b),則可以改寫表示式為ROUND(AVG(col), y)
。
使用演示
這裡我們採用 Bitcoin 的資料集對 DecimalV3 進行演示。
Bitcoin 的資料集部分示例如下:
- Unix - 時間戳
- Date - 時間
- Symbol - 時間序列資料所指代的交易品種
- Open - 該時間段的開盤價
- High - 該時間段的最高價
- Low - 該時間段的最低價
- Close - 該時間段的收盤價
- Volume BTC - BTC 金額
- Volume USD - USD 金額
以下是在 Doris 中的建表儲存資料,其中小數的列分別用 DecimalV3 進行儲存:
CREATE TABLE `btc` (
`unix` bigint(20) NOT NULL,
`date` datetime NULL,
`symbol` varchar(30) NULL,
`open` decimalv3(8, 2) NULL,
`high` decimalv3(8, 2) NULL,
`low` decimalv3(8, 2) NULL,
`close` decimalv3(7, 2) NULL,
`Volume_BTC` decimalv3(10, 8) NULL,
`Volume_USD` decimalv3(38, 30) NULL
) ENGINE=OLAP
DUPLICATE KEY(`unix`)
COMMENT 'OLAP'
DISTRIBUTED BY HASH(`unix`) BUCKETS 4
PROPERTIES (
"replication_allocation" = "tag.location.default: 1"
);
我們來計算一下 2022 年 1 月 1 日這一天的平均 Volume_BTC/Volume_USD 以及總的 Volume_BTC/Volume_USD:
mysql> select avg(Volume_BTC),avg(Volume_USD),sum(Volume_BTC),sum(Volume_USD) from btc where to_date(date)='2022-01-01';
+-------------------+--------------------------------------+-------------------+-----------------------------------------+
| avg(`Volume_BTC`) | avg(`Volume_USD`) | sum(`Volume_BTC`) | sum(`Volume_USD`) |
+-------------------+--------------------------------------+-------------------+-----------------------------------------+
| 0.51494486 | 24236.665942788256243957638888888888 | 741.52060313 | 34900798.957615088991299000000000000000 |
+-------------------+--------------------------------------+-------------------+-----------------------------------------+
通過 SQL 的執行結果可以看到,通過 DecimalV3,在 Volume_USD 這一列的平均結果和總和上,實現了保留 30 位的小數。而舊的 Decimal 型別在這個例子中只能實現保留不超過 20 位。
效能對比
我們採用 TPC-H Benchmark 100G 來對比 DecimalV3 與老版本 Decimal 的執行速度、儲存佔用、記憶體佔用等效能。
我們在兩個庫分別對新版 DecimalV3 和老版本 Decimal 進行建表。建表完成如下:
tpch1庫為DecimalV3
tpch2庫為老版本Decimal
執行速度
採用 TPC-H Benchmark 對執行速度進行測試:
select /*+SET_VAR(exec_mem_limit=8589934592, parallel_fragment_exec_instance_num=16, enable_vectorized_engine=true, batch_size=4096, disable_join_reorder=false, enable_cost_based_join_reorder=false, enable_projection=false) */
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;
tpch1庫(DecimalV3)的 SQL 執行結果為 6.38s
tpch2 庫(老版本 Decimal)的 SQL 執行結果為 8.13s
SQL Q1 所查詢的表是上述展示欄位的表 Lineitem,我們可以看到在 DecimalV3 的情況下,查詢 速度較老版本有 27.4% 的提升。
儲存佔用
tpch1庫(DecimalV3)的 Lineitem 表的儲存佔用為 18.475GB
tpch2 庫(老版本 Decimal)的 Lineitem 表的儲存佔用為 20.893GB
可以看到在有四個欄位由 Decimal 改為 DecimalV3 的情況下,儲存佔用有 13.1%的降低。
記憶體佔用
記憶體佔用測試我們同樣使用 Lineitem 表,採用自己改寫的一條 SQL
select count(*)
from
( select l_quantity,l_extendedprice,l_discount,l_tax
from lineitem
where l_shipdate < '1995-01-01'
group by l_quantity,l_extendedprice,l_discount,l_tax
)tmp;
下圖的 Grafana 監控中可以看到執行測試前的 Doris 記憶體穩定為 12.2GB
分別在兩個庫執行上述 SQL
在 tpch1庫(DecimalV3)下執行,記憶體佔用峰值為 26.6GB
記憶體回落正常後,在 tpch2 庫(老版本 Decimal)下執行,記憶體佔用峰值為 30.8GB
從上方三張圖中可以看到,這條 SQL 在 DecimalV3 的情況下不僅記憶體佔用降低了 15.8%,執行時間也縮短了10s。
總結
Apache Doris 1.2.1 版本推出的 DecimalV3 實現了更高的精度,更高的效能,更完備的精度推演,使得 Doris 更加適用於金融財務、科學計算等有精確計算需求的應用場景,結合 Apache Doris 強大的分析計算效能,給相關使用者及行業提供了更準確、完善的資料服務。
接下來,社群還將實現 JDBC 外表對 DecimalV3 型別的支援,JDBC Catalog 可以通過標準 JDBC 協議,連線其他資料來源,連線後 Doris 會自動同步資料來源下的 Database 和 Table 的元資料,以便快速訪問這些外部資料。基於 JDBC 的通用性,結合 Apache Doris 的 高效能分析能力,實現對各類資料庫資料聯邦查詢的高精度計算。
本文作者:
鍾永康,SelectDB 生態研發工程師
李文強,SelectDB 資料庫核心研發工程師,Apache Doris Committer
- Apache Doris 在美聯物業的資料倉庫應用實踐,助力傳統行業數字化革新!
- 杭銀消金基於 Apache Doris 的統一資料查詢閘道器改造
- 併發提升 20 倍、單節點數萬 QPS,Apache Doris 高併發特性解讀
- 如何基於 Apache Doris 與 Apache Flink 快速構建極速易用的實時數倉
- 從 Clickhouse 到 Apache Doris,慧策電商 SaaS 高併發資料服務的改造實踐
- 開源新生代的成長之路:從校園到開源,需要邁過哪些挑戰?
- 如何基於 Apache Doris 構建簡易高效的使用者行為分析平臺?
- 查詢效能較 Trino/Presto 3-10 倍提升!Apache Doris 極速資料湖分析深度解讀
- 資源消耗降低 90%,速度提升 50%,解讀 Apache Doris Compaction 最新優化與實現
- 從 ClickHouse 到 Apache Doris,騰訊音樂內容庫資料平臺架構演進實踐
- 一文教你玩轉 Apache Doris 分割槽分桶新功能
- 打破資料孤島,Apache Doris 助力縱騰集團快速構建流批一體數倉架構
- 實時分析全面賦能金融業務,馬上消費基於 Apache Doris 構建實時數倉的實踐
- 更高效能表現、更低資源佔用,高精度計算資料型別 DecimalV3 揭祕
- Java UDF 的設計與使用介紹,相容 Hive UDF 實現資料快速遷移
- 下一個十年,我們需要一款什麼樣的分析型資料庫?
- 更穩定!Apache Doris 1.2.1 Release 版本正式釋出|版本通告
- Apache Doris 在小米億級使用者行為分析平臺的實踐|最佳實踐
- 複雜查詢響應速度提升10 倍,度言軟體基於 Apache Doris 實時數倉建設實踐
- 併發提升 10 倍,運算延時降低 70%,領健從 ClickHouse 和 Kudu 到 Apache Doris 數倉升級實踐