本文介绍云数据库 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%内存占比。