Doris 的点查询优化功能,实测结果吓你一跳

来源:安瑞哥是码农


所谓的「点查询」,指的是在查询数据库表时,通过等值的条件筛选(where xxx=yyy),一般通过走索引的方式,以非常快的速度,获取到目标结果的查询方式。


一般对于数据库来说,如果你查询的条件走了索引,且符合条件的目标数据量很小的话,那么这个查询效率就会非常高。


至于说在已经利用了索引的基础上,还能玩出什么花来,Doris 宣称,它可以通过额外的一些设置,进一步实现查询加速。


那么今天这篇文章,就来一起看看这朵花,在针对 Doris 提到的点查询场景时,能开出什么样的颜色?



0. 官网描述


自 Doris 2.0 之后(当前进行测试的版本为2.1.2),官方提供了为点查询加速的「三板斧」,这三板斧分别是:


1. 开启行存:正常情况下 Doris 的数据都是以列的方式进行存储,这个所谓的行存,本质是另外开辟出一列,来存储整行的数据,理论上,是一个典型的「用空间换效率」的玩法;


2. 使用 PreparedStatement:这个应该是传统的 SQL 数据库都具备的特性,这里把它归结到可以用来加速点查询,个人认为有点牵强;


3. 开启行缓存:任何一个成熟的数据库,能够利用系统缓存(操作系统缓存,或者数据库进程空间的缓存)是一件特别正常的事情,不应该把这个作为自己查询加速的手段。而且,这个只能通过修改 BE 端的配置文件来实现,比较麻烦。


只不过这三板斧呢,除了第一把我觉得可能比较锋利,比较有兴趣之外,剩下的两把,等后面有时间了再试吧。


所以这次测试,咱就只针对这个开启行存」功能来展开。



1. 测试设计


还是用之前那份上网日志数据集,参考官网提供的测试样例,分别写到两张 UNIQUE 表里,其中一张开启点查询加速,另一张啥也不干(默认配置),然后对比同一个查询,看他们的效率分别如何。


找到一张数据量8亿+的测试母表,一共9个字段。


然后将这张表的数据,分别灌入到下面两张开启了「行存」的 UNIQUE 表,和没有开启行存功能的表。


开启了「行存」的 UNIQUE 表结构:


 CREATE TABLE `point_query_test01` (
  `client_ip` VARCHAR(200) ,
  `domain` VARCHAR(200) ,
  `time` VARCHAR(30) ,
  `target_ip` TEXT ,
  `rcode` INT NULL DEFAULT "99",
  `query_type` INT NULL DEFAULT "99",
  `authority_record` TEXT ,
  `add_msg` TEXT ,
  `dns_ip` TEXT 
ENGINE=OLAP
UNIQUE KEY(`client_ip``domain``time`)
COMMENT 'OLAP'
DISTRIBUTED BY HASH(`client_ip``domain``time`) BUCKETS 3
PROPERTIES (
"replication_allocation" = "tag.location.default: 1",
"enable_unique_key_merge_on_write" = "true",
"light_schema_change" = "true",
"store_row_column" = "true"
);


没开启「行存」的 UNIQUE 表结构:


 CREATE TABLE `point_query_test02` (
  `client_ip` VARCHAR(200) ,
  `domain` VARCHAR(200) ,
  `time` VARCHAR(30) ,
  `target_ip` TEXT ,
  `rcode` INT NULL DEFAULT "99",
  `query_type` INT NULL DEFAULT "99",
  `authority_record` TEXT ,
  `add_msg` TEXT ,
  `dns_ip` TEXT 
ENGINE=OLAP
UNIQUE KEY(`client_ip``domain``time`)
COMMENT 'OLAP'
DISTRIBUTED BY HASH(`client_ip``domain``time`) BUCKETS 3
PROPERTIES (
"replication_allocation" = "tag.location.default: 1"
);



2. 灌数据


先看开启了行存功能的表,数据写入的情况:




耗时 17 分 36 秒


再看没有开启行存功能表的数据写入情况:




耗时 9 分 06 秒


从写入耗时来看,开启了行存功能的表,其写入时间,几乎是没有开启行存表的两倍。


在数据量一样的情况下,再对比一下这两张表所占用的存储大小:


可以看到,开启了行存功能的存储占用,是没有开启行存的3倍还多。



3. 查询效率对比


既然数据写入效率更慢,而且占用的存储也更多,那我们接下来倒要看看,对于开启了行存功能的表来说,这亏欠的两个部分,到底能不能从查询效率上,给找补回来?


官网对这个能利用到行存功能的条件(短查询路径),是必须要对 key 进行等值筛选,但它没有详细说明,当这个 key 是组合字段时(当前测试的表就是3个字段的组合 key),我可不可以基于「最左原则」,也能利用到这个功能的便利性。


如果筛选条件可以基于「最左原则,那说明这个功能设计的还算正常,而如果不行,只能说明这个设计太失败了(一般情况下应该不会)


但不管它如何设计,下面我将根据人类使用索引的正常逻辑,遵循 where 条件中,字段筛选的「最左原则」进行测试。


点查对比1


查询 SQL(where 条件含 key 中1个字段情况下):


 select * from point_query_test where client_ip='19.168.200.160

开启了行存功能的效率:



没有开启行存的效率:


你可能会说,单次测试说明不了什么问题,但事实是,我换了多个不同的 client_ip 测试了多次,结果一样


测试小结:开启了行存的查询效率,都没能干过不开启行存的,挑战失败(数量级的差别)


点查对比2


查询 SQLwhere 条件含 key 中2个字段情况


select * from point_query_test where client_ip='192.168.200.115' and domain='qq.coM.'

开启行存功能的效率


没有开启行存的效率


同样的,这一次我还是把查询字段中的值换了多个,依然是前者的效率,不如后者。


测试小结:开启了行存的查询效率,干不过不开启行存的(数量级的差别)


点查询对比3


查询 SQL(where 条件含所有 key 字段情况


select * from point_query_test where client_ip='192.168.100.87' and domain='www.BaIdU.CoM.' and time='20230706081205';

开启行存功能的效率



没有开启行存的效率


也是一样,换了多个不同的查询值,两者的执行效率依然是同样的水平。


测试小结:还是一样,开启了行存的查询效率,依然干不过不开启行存的(数量级的差别)。


点查询对比4


查询 SQL(where 条件为非 key 字段


select * from point_query_test where target_ip='8.7.198.46';

开启行存功能的效率


没有开启行存的效率


小结:在查询条件不包含 key 的字段情况下,查询效率打平


以上的查询效率对比,取的都是各自第一次查询出结果的时间,因为只有这样才最有意义。


当然,我也测试过同一个查询条件,后续再次查询的效率,估计是受系统缓存的影响,两者的后续查询效率几乎一致。



最后


从这次针对点查询优化而开启的行存功能实测表现来看(仅针对当前数据场景),对于同样的一份数据集,在开启了行存情况下,数据写入效率变低(大概减半),且存储空间更大(是原来的3倍)。


但是,即便如此,却并没有换来该有的「点查询」效率变高,而且恰恰相反,变更低了(是我使用的姿势不对吗?)。


老实说,对比到这里,我心里都开始有点慌了,怀疑自己是不是眼花,把测试结论给整反了,在反复确认之后,才算松了一个口气。


也不知道是不是我的测试场景过于与众不同,从以往测试过那么多 Doris 推出的,有关查询优化的功能来看,能做到不打脸的,好像还真不多。


我想说实测,才是检验一个功能到底行不行最有说服力的标准,没有之一。


至于说在高并发情况下,这种优化是不是真的有效,还期待你们的检验。

请使用浏览器的分享功能分享到微信等