首先说明:
select count(*) 和 select count(1)的效率相差无几。

这里开始引用自“德哥@Digoal”的博客,原文链接:http://blog.163.com/digoal@126/blog/static/163877040201331252945440/

–引用部分开始–

引用块内容
PostgreSQL 的count确实是一大软肋, 特别是全表的count.
在9.2以前全表的count只能通过扫描全表来得到, 即使有pk也必须扫描全表.
9.2版本增加了index only scan的功能, count(*)可以通过仅仅扫描pk就可以得到.
但是如果是一个比较大的表, pk也是很大的, 扫描pk也是个不小的开销.
那么有没有办法来优化count全表的操作呢, 如果你的场景真的有必要频繁的count全表, 那么可以尝试一下使用以下方法来优化你的场景.
其实非常简单, 就是给表建立几个触发器, 每次插入,删除,truncate表时触发, 将表的记录数更新到一个记录表中.
但是要知道, 这样会带来一个问题, 并发的插入和删除操作, 如果仅仅使用1条记录来存储表的count(*)值的话, 会有严重的锁冲突的问题.
例如两个session ,同时插入1条记录, 在触发触发器时, 由于都要更新count表的同一条记录, 那么会发生行锁等待.
因此, 可以使用多条记录来缓解行锁冲突的问题, 如下 :
创建测试表, a, 假设要经常count(*) from a.

create table a(id serial4 primary key, info text, crt_time timestamp(0) default now());

创建记录a表记录数的表

create table cnt_a(id int primary key, cnt int);

为了缓解行锁冲突, 这里使用了1001条记录来存储count(*) from a的值.

insert into cnt_a select generate_series(0,1000),0;

在计算count(*) a时, 使用sum(cnt) from cnt_a就可以了. 因此只需要扫描1001行.
后面会看到当a表的记录数越多, 性能提升约明显.
创建插入/删除/truncate触发器

CREATE OR REPLACE FUNCTION public.tg_insert_a()RETURNS triggerLANGUAGE plpgsql
AS $function$
declarem_id int;rm numeric;
beginselect max(id),random() into m_id,rm from cnt_a;update cnt_a set cnt=cnt+1 where id=(rm*m_id)::int;return null;
end;
$function$;CREATE OR REPLACE FUNCTION public.tg_delete_a()RETURNS triggerLANGUAGE plpgsql
AS $function$
declarem_id int;rm numeric;
beginselect max(id),random() into m_id,rm from cnt_a;update cnt_a set cnt=cnt-1 where id=(rm*m_id)::int;return null;
end;
$function$;CREATE OR REPLACE FUNCTION public.tg_truncate_a()RETURNS triggerLANGUAGE plpgsql
AS $function$
declare
beginupdate cnt_a set cnt=0 where not cnt=0;return null;
end;
$function$;create trigger tg1 after insert on a for each row execute procedure tg_insert_a();
create trigger tg2 after delete on a for each row execute procedure tg_delete_a();
create trigger tg3 after truncate on a for each statement execute procedure tg_truncate_a();

插入以下记录后,测试完后通过count(*) 和sum(cnt)比对数据是否一致

postgres=# select count(*) from a;count
---------1755964
(1 row)
Time: 285.491 ms
postgres=# select sum(cnt) from cnt_a ;sum
---------1755964
(1 row)
Time: 0.689 ms

当记录数到达千万级别后, 性能以及提升几千倍了.

–引用部分开始–

“德哥@Digoal”又做了一些后续的优化,详情可点击链接自行移步查看:http://blog.163.com/digoal@126/blog/static/163877040201331252945440/

我在实际应用中也发现了其中存在死锁现象,认为是触发器函数中select的“Shared Lock”和update的“Exclusive Lock”竞争产生的。详见我的博客:《Transaction中的SQL死锁》http://blog.csdn.net/fm0517/article/details/52242285

于是我也做了一些改进,即:假设表cnt_a中的记录数是固定的,所以在insert触发器和delete触发器中,不再从cnt_a中去取max(id),从而避免了死锁。
改进的触发器函数:

CREATE OR REPLACE FUNCTION tg_insert_a()RETURNS triggerLANGUAGE plpgsql
AS $function$
declarerm numeric;
beginselect random() into rm;update trigger_cnt set cnt=cnt+1 where id=(rm*1000)::int;return null;
end;
$function$;CREATE OR REPLACE FUNCTION tg_delete_a()RETURNS triggerLANGUAGE plpgsql
AS $function$
declarerm numeric;
beginselect random() into rm;update trigger_cnt set cnt=cnt-1 where id=(rm*1000)::int;return null;
end;
$function$;

最后值得注意的是:该方法虽然在大数据量的情况下能够大幅提高select count(*)的效率,但是增加了insert和delete时数据库的负担。所以使用时要谨慎综合考虑实际情况再做决定。

Select count(*) 的优化相关推荐

  1. mysql innodb count_MySQL下INNODB引擎的SELECT COUNT(*)性能优化及思考

    正 文: MySQL下INNODB引擎的SELECT COUNT(*)性能优化及思考 最近有项目有高并发需求,服务器采用负载均衡,数据库采用阿里云的RDS MYSQL,16核64G内存,连接数:160 ...

  2. mysql sum 慢_故障分析 | MySQL 优化案例 - select count(*)

    作者:xuty 本文来源:原创投稿 *爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源. 本文关键字:count.SQL.二级索引 一.故事背景 项目组联系我说是有一张 50 ...

  3. select count(*) from返回值_MySQL 优化:count(1)真的比count(*)快吗

    在实际项目开发中一定会有统计记录数的需求,比如统计用户数,像一些电商系统后台首页会统计订单量.上架商品数量等等,涉及到统计就离不开聚合函数 count() ,开发中常用写法如下: select cou ...

  4. mysql select count 5万条数据很慢_mysql亿级数据数据库优化方案测试银行交易流水记录的查询...

    点击上方△蓝字关注我们 带你征服编程和泡妞两座大山 对MySQL的性能和亿级数据的处理方法思考,以及分库分表到底该如何做,在什么场景比较合适? 比如银行交易流水记录的查询 限盐少许,上实际实验过程,以 ...

  5. 我说 SELECT COUNT(*) 会造成全表扫描,面试官让我回去等通知

    来自:码海 前言 上篇 SQL 进阶技巧(下) 中提到使用以下 sql 会导致慢查询 SELECT COUNT(*) FROM SomeTable SELECT COUNT(1) FROM SomeT ...

  6. 你知道select count(*)底层究竟干了啥么?

    作者:贾春生 https://blog.didiyun.com/index.php/2019/01/08/mysql-count/ "SELECT COUNT( * ) FROM T&quo ...

  7. select count(*)加其他字段_count(1)、count(*) 与 count(列名) 的执行区别

    (给ImportNew加星标,提高Java技能) 作者:BigoSprite blog.csdn.net/iFuMI/article/details/77920767 执行效果: 1.  count( ...

  8. MySQL:SELECT COUNT 小结

    作者 | 翁智华 来源 | https://www.jianshu.com/p/4913fdd1e277 背景 今天团队在做线下代码评审的时候,发现同学们在代码中出现了 select count(1) ...

  9. mysql的count(*)的优化,获取千万级数据表的总行数

    一.前言 这个问题是今天朋友提出来的,关于查询一个1200w的数据表的总行数,用count(*)的速度一直提不上去.找了很多优化方案,最后另辟蹊径,选择了用explain来获取总行数. 二.关于cou ...

最新文章

  1. OpenStack监控测量服务Ceilometer安装及 API说明
  2. mybatis做批量删除时写SQL语句时遇到的问题
  3. 【Python】机器学习绘图神器Matplotlib首秀!
  4. 零宽断言java_正则表达之零宽断言(零宽度正预测先行断言)
  5. 2018年10月28日宁波dotnet社区活动回顾及下次活动预告
  6. iframe高度自适应(IE6+、FF、Opera、Chrome等测试通过)
  7. Struts2国际化
  8. svo: semi-direct visual odometry 论文解析
  9. 站长吧asp工具设置_网站更换域名需要怎么办?网站更换域名如何设置?
  10. 教学转用计算机,一种计算机教学用旋转显示屏的制作方法
  11. Oracle redo解析之-1、oracle redo log结构计算
  12. jenkins with ant 和 invoke ant
  13. GO语言中中文占3个字节,英文占1个字节
  14. 手把手教你在 Vue 中使用 JSX,不怕学不会!【建议收藏】
  15. 关于win8的各种版本的区别
  16. Spring Boot 3.0.0-M1 Reference Documentation(Spring Boot中文参考文档) 9-16
  17. iPhone卫星功能仅用于紧急通信;韩国通过立法禁止苹果、谷歌垄断支付系统;Linux 5.14 版本发布|极客头条
  18. The Softer Side of the Architect
  19. OpenGL ES 2.0 for Android教程(九):添加触摸反馈
  20. python中arch模块_在Arch下安装pip

热门文章

  1. 一个权限管理模块的设计(转载)
  2. 问题小结(2)-dialog内容动态变化(调用系统方法时)
  3. 30幅非常精美的海景摄影作品欣赏
  4. 三维图----2(房子)
  5. Linq to sql查询句法
  6. nginx日志分析查询异常请求IP之狙击网络黑客
  7. Node.js 将Json文件数据转为SQL可执行的insert语句
  8. Python 懂车帝车友圈--分析与实现
  9. PHPRunner(网页制作工具)v10.3中文版
  10. for、forEach、map、for...in、for...of的区别以及能否终止循环的总结