本文介紹云數據庫 SelectDB 版中高并發點查相關優化設計和使用指南,幫助您優化查詢并發和響應延時。
背景
在高并發服務場景中,一般是從系統中獲取整行數據。而SelectDB基于列存構建,當表較寬時,列存格式將大幅放大隨機讀取IO,造成查詢速度下降。SelectDB的優化器和執行引擎,對于某些簡單的查詢(如點查詢)來說過于繁重,需要SelectDB查詢優化器具備規劃短路徑的能力來處理這樣的查詢。此外,SelectDB的查詢入口層使用Java編寫,分析和解析高并發查詢SQL也會導致高CPU開銷。為了解決這些問題,SelectDB引入了行存、短查詢路徑、PreparedStatement來解決這些問題。
行存
可以在SelectDB表中開啟行存模式,但是需要消耗額外的存儲空間。目前的行存實現是將行存編碼后存在單獨的一列中,這樣做簡化了行存的實現。行存模式僅支持在建表的時候開啟,需要在建表語句屬性(property)中指定如下屬性。
"store_row_column" = "true"
在Unique模型下的點查優化
在Unique數據模型下使用行存時,開啟Merge-On-Write策略以減少點查時的IO開銷。當enable_unique_key_merge_on_write
與store_row_column
在創建Unique表的語句中被設置為開啟時,對于主鍵的點查會采用短路徑規劃來對SQL執行進行優化,僅需要執行一次RPC即可執行完成查詢。
例如在一個高并發點查場景下,在Unique模型中開啟行存、Merge-On-Write策略。
CREATE TABLE `tbl_point_query` (
`key` int(11) NULL,
`v1` decimal(27, 9) NULL,
`v2` varchar(30) NULL,
`v3` varchar(30) NULL,
`v4` date NULL,
`v5` datetime NULL,
`v6` float NULL,
`v7` datev2 NULL
) ENGINE=OLAP
UNIQUE KEY(`key`)
COMMENT 'OLAP'
DISTRIBUTED BY HASH(`key`) BUCKETS 16
PROPERTIES (
"enable_unique_key_merge_on_write" = "true",
"light_schema_change" = "true",
"store_row_column" = "true"
);
推薦開啟
enable_unique_key_merge_on_write
,以方便存儲引擎根據主鍵來進行快速點查。當條件只包含主鍵時,例如
select * from tbl_point_query where id = 123
,類似的查詢會采用短路徑規劃來優化查詢。推薦開啟
light_schema_change
,因為主鍵點查的優化依賴了輕量級Schema變更中的column unique id
來定位列。點查只支持單表Key列等值查詢,不支持Join、嵌套子查詢。where條件里需要有且僅有Key列的等值,可以認為是一種鍵值對查詢。
使用PreparedStatement
為了減少SQL解析和表達式計算的開銷,SelectDB查詢入口層提供了與MySQL協議完全兼容的PreparedStatement
特性(目前只支持主鍵點查)。若在FE開啟PreparedStatement
,SQL和其表達式將被提前計算并緩存到Session級別的內存緩存中,后續的查詢直接使用緩存對象即可。當CPU成為主鍵點查的瓶頸時,在開啟PreparedStatement
后,將會有4倍以上的性能提升。
例如在JDBC中使用PreparedStatement
。
設置JDBC URL并在Server端開啟
PreparedStatement
。url = jdbc:mysql://127.0.0.1:9030/ycsb?useServerPrepStmts=true
使用
PreparedStatement
。// use `?` for placement holders, readStatement should be reused PreparedStatement readStatement = conn.prepareStatement("select * from tbl_point_query where key = ?"); ... readStatement.setInt(1234); ResultSet resultSet = readStatement.executeQuery(); ... readStatement.setInt(1235); resultSet = readStatement.executeQuery(); ...
開啟行緩存
SelectDB中有針對Page級別的內存緩存(Page Cache),每個Page中存儲的是某一列的數據,這意味著Page Cache是針對列的緩存。對于前面提到的行存,一行里包括了多列數據,緩存可能被大查詢給刷掉,為了增加行緩存命中率,SelectDB單獨引入了行存緩存。行緩存復用了SelectDB中的LRU Cache機制來保障內存的使用,通過指定如下的BE配置來開啟。
disable_storage_row_cache
是否開啟行緩存,考慮內存開銷,默認值為true,不開啟行緩存。row_cache_mem_limit
指定Row Cache占用內存的百分比,默認值為20,代表20%內存占比。