本文介紹ApsaraDB for 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%記憶體佔比。