[TOC]
简介
最近在基于es的id查询时有个困惑,基于id的get查询和基于id的query查询查询速度是否一样;如果不一样又是因为什么不一样?带着这2个疑问我进行了一些分析,下面进行展示
2种查询压测对比
准备工作
下面进行实际压测对比
- index:
*种压测使用的index是同一个index,数据量为千万级别 - 数据:
使用的不同的id作为压测数据,避免有缓存造成结果不准确 - 工具:
使用wrk1 进行压测,wrk是一个现代化的压测工具,可以结合lua进行一些动态数据压测。
基于get id查询
wrk -t1 -c1 -d10s --scripts=get.lua --latency urlxxx
wrk -t1 -c1 -d10s --scripts=query.lua --latency urlxxx
结果说明
基于上面的实验结果可以看出,直接基于id的查询90%基准会比基于普通query查询效率高出2-3倍,我的第一个问题解决了。
为什么基于id的get请求会更快
上面的实验结果表明直接基于id的get查询效率更高,但是为什么会这样?这得从es底层的数据存储和查询过程说起,可能不同版本间有差异,说的不一定全对,还请各位看客海涵,如果有问题请提出。
es的数据存储
我们以一个例子先来讲讲es存储的几个概念 2
例如我们有一个user表它有四个字段:分别是name,gender,age,address。画出来的话,大概是下面这个样子,跟关系型数据库一样
- docid
每个文档的唯一性标志 - doc
一条记录就是一个文档 - term:
一段文本经过分析器分析以后就会输出一串单词,这一个一个的就叫做Term(直译为:单词) - posting list
维护的是哪些 docid出现在该term中 - term dictionary
将一列的所有的term进行排序后维护的一个词典就叫term dictionary,查询某个term的时候就可以进行二分法查询(logn复杂度,mysql的b-tree索引就是这一层,但是es还会把term dictionary利用fst 再建立一个 term index放到内存,索引查询会更快) - term index
为了更快的找到某个单词,我们为term dictionary建立索引
例如上面的name 列表维护的一个term dictionary就是
es的查询过程 3
- query查询
es的查询分为2个过程 query和fetch
query过程就是上面的从 term index -> term dictionary --> posting list,再根据docid获取到对应的文档
fetch过程 再根据各个分片汇总的数据进行排序,再去各节点获取数据 - get id查询
get 过程是从 内存 translong–> 磁盘translog --> 根据docid直接获取文档
从上面过程可以看出get的获取数据更新,更快
其他
上面是基于id的get查询的分析,但是都是针对单个id的;针对多个id的mget查询和ids query是否有类似的差异呢?通过实验发现基于多个id的查询,mget的效率高于ids query。
# 参考