背景形容:
组内我的项目有一张表叫做 Session,记录的是每一条测试的详细信息,包含 id,创建者,创立工夫,测试时长,测试状态(FINISH,TESTING,NO_FRAME 等),还有 Properties(是一个大 json,也就是什么字段都能够往里面塞,例如我的项目包名,软件版本号,测试各项配置)等。
当初须要加一个性能,这个性能是在 admin 页面上,也就是后盾治理页面上做的。当你在页面上 hover 某条测试的包名(例如:com.hhh.goodgame)的时候,须要显示该测试包,在咱们我的项目内实现了多少次测试。
最开始的做法就是失常的调用 ListSession 函数,并传入参数进去,取得 api 返回的 count 数。
http.listSessions({equalPackageName:searchedSession.Properties.packageName,testStatus:'FINISHED', withDelete: true})
然而,因为 Session 列表的数目过于大,有 15w 条数据,所以每次查问速度都很慢。于是,咱们决定在 Properties.packageName 字段下面,建设一个索引。最开始的时候,我还在纠结能不能给字段的字段建设索引,起初查了一下,PSQL 真的很弱小,它能够反对:表达式索引。
create index idx_session_properties_packagename on upa.profilingsession ((properties ->> 'packageName'));
建设好索引之后,就是验证它是否失效了。在将我的 liquibase 批改推向 master 分支之前,我在本地的数据库里进行了模仿。
点开表的详情曾经能够看失去了。而后,决定再用 explain 试一下,看看 index 是否有被好好应用,然而后果如下图所示。
而后,我就很奇怪,为什么明明表详情内曾经能够看到 index idx_session_properties_packagename,然而搜寻的时候却没有用上。于是猜测,是不是因为我本地表内数据只有 7 行,数据量太小了?于是我怒插 20 行,最终失去了如下图所示的后果。
总结学习:
1)新增的 index 並沒有在 query plain 裡面。為什麼 postgres 不選擇 index scan 卻選擇 seq scan?
在數據量很小的時候,seq scan 會比 index scan 更加无效。
pgsql 的 query plan 有一個評估值的形式來“預測”哪一種形式比較快。index scan 至多要發生兩次 I/O,一次是讀取索引塊,一次是讀取數據塊,代價遠高於 seq can。當 index 很大的時候,情況可能會更加複雜。
2)postgresql 中的各种 scan 的比拟
- Seq Scan(就是依照表的记录的排列程序从头到尾顺次检索扫描,每次扫描要取到所有的记录。这也是最简略最根底的扫表形式,扫描的代价比拟大)
- Index Scan(对于给定的查问,咱们先扫描一遍索引,从索引中找到符合要求的记录的地位(指针),再定位到表中具体的 Page 去取。等于是两次 I /O,先走索引,再走取表记录,不同于全表扫描的是只取所需数据对应的 Page,I/ O 量较小)
- Bitmap Heap Scan(当 PostgreSQL 须要合并索引拜访的后果子集时 会用到这种形式,通常状况是在用到 “or”,“and”时会呈现 ”Bitmap heap scan”)
- index only scan(建设 index 时,所蕴含的字段汇合,囊括了咱们查问语句中的字段,这样,提取出相应的 index,就不用再次提取数据块了)
- 当获取的数据分布很大 (比方 70% 以上) 时,用 index scan 曾经没有意义了,因为数据太多了,走索引再走表的代价曾经超过了单纯走表的代价了。就不如用全表扫描了。
- 而数据分布较小(比方 1.7%),则索引的劣势就体现进去了。可能 bitmap index scan 的性能就更好(相比于 index scan,因为它缩小了 index 的反复扫描)。
- 当数据更少的时候,用 index scan 可能就更好(索引反复的可能性较小且回避了在内存中排序的代价)。