最近项目遇到了一个单表查询慢的情况,需要优化。原因是 group by 和 limit 一起用的时候索引不生效,我的解决方法是用子查询,这样索引生效了,查询速度也变快了。
于是我又做了一些其他的测试,这里记录一下我测试分析的过程。ps:懒得造数据了,表名我打马赛克了
1.因为查询条件需要 create_user_id(有 btree 索引),所以先对表的 create_user_id 进行分组统计条数
select create_user_id,count(*) as user_count from mytable group by create_user_id
ORDER BY user_count desc
取 50500,52200,51800 的数据查询
2.直接查询
原始查询都没有用到索引,意料之之中
3.子查询
关于这个问题我就是用子查询解决的,但是这里却没有用到索引???于是我对比了我解决问题的 sql 和这个 sql 的不同,发现我这里是用了 select * ,于是
这里还是没有用到索引?郁闷了一会,在对比一下。发现原来的是 select id || '' 而不是 select id, 于是
这里果然是用到了索引,但是我不明白为什么“select id || '' ”会用索引,但是“select id”不用索引,网上资料说是 pg 在查询时有自己一套策略,会根据当前 sql 情况决定执行方式。但是我不懂这里明明用了索引更快了才对,而且我拼接空字符串应该也要额外消耗吧。可是结果反而是更快了,😳 。
继续测试,还是这个 sql,id 换成 50500
可以看到不使用索引了,结合我今天查到的资料,应该是 pg 认为这次的查询返回的结果集较多(配合第一张图看),因此不使用索引。
id 用 51800 替换再试试
有使用索引,和预期的一样
4.用 with 语句
这里的预期结果和子查询差不多,不同在于 with 比子查询在查询同样条件下会快一些。还有就是 with 的查询不能用“select id || '',会报错。
最后我的结论是:
1.pg 的 group by 和 limit 共用的时候确实会导致索引不生效,可以用子查询或者 with 语句解决
2.pg 的 sql 执行策略决定是否使用索引的因素有很多,比如返回结果集占该表百分比的大小(试过在其他数据库数测试测试返回结果集也是 20 多万但是占总表百分比没这么大,也用了索引),select 部分内容的写法(这里我并不理解为什么)以及其他。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于