Select count(*) 的优化
首先说明: 这里开始引用自“德哥@Digoal”的博客,原文链接:http://blog.163.com/digoal@126/blog/static/163877040201331252945440/ –引用部分开始–
create table a(id serial4 primary key,info text,crt_time timestamp(0) default now());
create table cnt_a(id int primary key,cnt int);
insert into cnt_a select generate_series(0,1000),0;
CREATE OR REPLACE FUNCTION public.tg_insert_a() RETURNS trigger LANGUAGE plpgsql AS $function$ declare m_id int;
rm numeric;
begin select 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 trigger LANGUAGE plpgsql AS $function$ declare m_id int;
rm numeric;
begin select max(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 trigger LANGUAGE plpgsql AS $function$ declare begin update 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();
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://www.52php.cn/article/p-ugjukbzh-zp.html 于是我也做了一些改进,即:假设表cnt_a中的记录数是固定的,所以在insert触发器和delete触发器中,不再从cnt_a中去取max(id),从而避免了死锁。 CREATE OR REPLACE FUNCTION tg_insert_a() RETURNS trigger LANGUAGE plpgsql AS $function$ declare rm numeric;
begin select 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 trigger LANGUAGE plpgsql AS $function$ declare rm numeric;
begin select random() into rm;
update trigger_cnt set cnt=cnt-1 where id=(rm*1000)::int;
return null;
end;
$function$;
最后值得注意的是:该方法虽然在大数据量的情况下能够大幅提高select count(*)的效率,但是增加了insert和delete时数据库的负担。所以使用时要谨慎综合考虑实际情况再做决定。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |