1. 简介
HypoPG是一个可以创建“虚拟/虚假”索引的插件,让你不用建立真实的索引,就可以让你事先判断出在一些字段上建索引是否有效的插件。
通常加索引是一个比较有效的优化方法,但是对于一些复杂的SQL,在表上加索引有没有效果是难以很快判断的,需要更多的一些知识,如需要了解数据分布、输入条件、列的唯一值等等情况来判断,而使用HypoPG则不需要这么复杂的判断了,通过HypoPG创建虚拟索引,然后看复杂SQL的执行计划就可以判断出建索引是否有效了。所以对于没有DBA的公司这个插件可以帮助开发人员快速确定是否该加索引,对于有DBA的公司也可以节省DBA的时间。
HypoPG的源代码放在github上:
官方文档:
我们下面就会详细演示HypoPG的使用。
2. 安装HypoPG
如果你的PostgreSQL是使用yum安装的官方的PostgreSQL版本,则可以直接用yum安装HypoPG这个插件:
yum install hypopg
如果从源码安装,则:
先使用git把源码从github上拉下来:
git clone https://github.com/dalibo/hypopg.git
查看版本标签:
[root@pg01 hypopg]# git tag0.0.10.0.20.0.30.0.40.0.51.0.01.1.0
选择一个版本,通常选择最新版本,这里选择1.1.0:
git checkout 1.1.0
然后编译安装即可:
makemake install
3. 使用
在数据库创建插件:
CREATE EXTENSION hypopg;
建测试表:
postgres=# CREATE TABLE hypotest AS SELECT seq as id, ('osdba ' || seq)::text as t FROM generate_series(1,100000) as seq;SELECT 100000
查看没有索引时全表扫描的代价:
postgres=# explain select * from hypotest where id=1228;QUERY PLAN------------------------------------------------------------Seq Scan on hypotest (cost=0.00..1791.00 rows=1 width=15)Filter: (id = 1228)(2 rows)
建虚拟索引:
postgres=# \timingTiming is on.postgres=# SELECT hypopg_create_index('CREATE INDEX ON hypotest (id)');hypopg_create_index----------------------------------(16635,<16635>btree_hypotest_id)(1 row)Time: 0.446 mspostgres=#
因为虚拟索引是一个假的,建立时即不占用CPU,也会实际占用磁盘空间,故从上面可以看到很快就把虚拟索引建好了。
这时我们再用explain来查看执行计划:
postgres=# EXPLAIN SELECT * FROM hypotest WHERE id = 1228;QUERY PLAN------------------------------------------------------------------------------------------Index Scan using <16635>btree_hypotest_id on hypotest (cost=0.04..8.06 rows=1 width=15)Index Cond: (id = 1228)(2 rows)Time: 0.350 ms
发现执行计划变成了走索引:
Index Scan using <16635>btree_hypotest_id on hypotest (cost=0.04..8.06 rows=1 width=15)
如果我们真实执行此条SQL(在explain中加analyze):
postgres=# EXPLAIN ANALYZE SELECT * FROM hypotest WHERE id = 1228;QUERY PLAN------------------------------------------------------------------------------------------------------Seq Scan on hypotest (cost=0.00..1791.00 rows=1 width=15) (actual time=0.145..6.661 rows=1 loops=1)Filter: (id = 1228)Rows Removed by Filter: 99999Planning time: 0.037 msExecution time: 6.684 ms(5 rows)Time: 7.021 ms
从上面可以看到真实的执行还是走全表扫描的执行计划,这就是HypoPG的作用,HypoPG的虚拟索引只是影响非真实执行的explain的结果,而不会改变SQL执行时的真实执行计划。
HypgPG还提供了一些函数用于查看、删除虚拟索引等操作:
查看有哪些虚拟索引:
postgres=# SELECT * FROM hypopg_list_indexes();indexrelid | indexname | nspname | relname | amname------------+--------------------------+---------+----------+--------16635 | <16635>btree_hypotest_id | public | hypotest | btree(1 row)Time: 3.310 ms
估算此真正建立后会有多大:
postgres=# SELECT indexname, pg_size_pretty(hypopg_relation_size(indexrelid)) FROM hypopg_list_indexes();indexname | pg_size_pretty--------------------------+----------------<16636>btree_hypotest_id | 2544 kB(1 row)Time: 1.029 ms
获得建索引的DDL语句:
postgres=# select hypopg_get_indexdef(16636);hypopg_get_indexdef--------------------------------------------------CREATE INDEX ON public.hypotest USING btree (id)(1 row)Time: 0.294 ms
删除虚拟索引:
postgres=# select hypopg_drop_index(16635);hypopg_drop_index-------------------t(1 row)Time: 0.409 mspostgres=# SELECT * FROM hypopg_list_indexes();indexrelid | indexname | nspname | relname | amname------------+-----------+---------+---------+--------(0 rows)Time: 0.601 ms
也可以调用hypopg_reset()函数把所有的虚拟索引都删除掉:
postgres=# select hypopg_reset();hypopg_reset--------------(1 row)