Postgresql在执行count(*)分区表时获得错误的估计行,仅扫描索引

3df52oht  于 12个月前  发布在  PostgreSQL
关注(0)|答案(2)|浏览(94)

我有一个Azure Flexible Postgresql大型分区表版本13,我需要从该表运行count()并与Oracle性能进行比较。但是,在检查解释计划后,我有一些问题,如下所示
1.解释计划已使用“仅索引扫描”获取数据,但总是获取错误的估计行(20954927 vs 16763942)
https://explain.depesz.com/s/CmTi
->在stat_201408上使用stat_201408_acct_id_idx进行仅并行索引扫描(成本=0.44..579554.83行=20954927宽度=0)(实际时间=0.017..1218.683行=16763942循环=3)
SELECT reltuples::bigint,relpages,relallvisible FROM pg_class WHERE relname = 'stat_201408';
关系组|再页|可见的
-----------+----------+---------------
50291824 | 470018 | 470018
select count(
)from stat_201408;
50291825(1排)
甚至我尝试将列acct_id上的统计信息增加到3000,但这没有帮助
ALTER TABLE stat_201408 ALTER COLUMN ACCT_ID SET STATISTICS 3000;
真空分析详细stat_201408;
我只是在一个分区上进行测试,所以整个分区表的差异很大
1.在这个表上,我有一些索引如下,但我不清楚为什么它总是使用stat_idx1(列acct_id),其值低于stat_efftv_dt_acct_id_idx
指标:

"stat_batch_id_idx" btree (batch_id)
"stat_efftv_dt_acct_id_idx" btree (efftv_dt, acct_id)
"stat_idx1" btree (acct_id)
"stat_idx7" btree (batch_id, stat_cd)

字符串
下面是某些列上的非重复值的数量
从wmcb_int.acct_stat_201408选择计数(DISTINCT acct_id)、计数(DISTINCT efftv_dt)、计数(DISTINCT batch_id);
帐户ID| efftv_dt|批次标识
---------+-------+-------
1271151 | 21 | 21
此分区的某些列的统计信息

tablename     |   attname    | total_rows | correlation


------------------+--------------+------------+-------------
201408年|批次标识| 50291824 |0.9995212
201408年|efftv_dt| 50291824 |0.9995212
201408年|acct_stat_cd| 50291824 |0.051139828
201408年|帐户ID| 50291824 |0.044063628
(4行)
我的问题是
1.如何修复解释计划中错误的估计行
1.如何通过HINT作为Oracle在PostgreSQL查询中强制使用特定索引
1.一个列的非重复值的数量将决定应该选择哪个索引吗?如何找出哪些列需要被索引以获得最佳性能,而count(*)
非常感谢

lp0sw83n

lp0sw83n1#

当运行并行查询时,假设不是所有工作进程都将处理完全相同数量的行,因为行不是一个接一个地划分,而是按块或块范围划分;一般来说,不是所有的区块都有相同数量的活动行。规划者通过夸大估计的行数来解释这一点,假设总查询时间将由最慢的工作者驱动,并且最慢的工作者将是具有最多行的工作者。
这是按设计运行的。没有办法(也没有理由,据我所知)“修复”它除了黑客的代码和重新编译。
有一个第三方扩展,pg_hint_plan,你可以用它来给PostgreSQL添加Oracle风格的提示。尽管在这种情况下很难看出你希望通过这样做来实现什么。
如果你不想安装pg_hint_plan,你可以通过删除你不想使用的索引来测试替代索引,看看它会做什么。如果你不想重新构建删除的索引,你可以在一个事务中删除它,运行EXPLAIN,然后回滚删除。
很难看出你希望通过这一切来完成什么。从Oracle过渡到PostgreSQL本身就会带来足够多的真实的麻烦,没有理由去幻想那些想象中的麻烦。

eufgjt7s

eufgjt7s2#

我尝试强制使用stat_efftv_dt_acct_id_idx(列efftv_dt,acct_id)的方式如下,它实际上得到了更好的实际执行时间,但它是回滚所有完成查询后,并从磁盘IO读取在下一次运行,而不是利用共享缓冲区命中从最后一次运行我担心的是,我不想放弃“stat_idx1”(acct_id)因为它需要用于一些带有 predicate acct_id的查询。
开始;
drop index stat_idx1;
EXPLAIN(analyze,verbose,costs,timing,buffers)select count(*)from stat_201408;
回滚;

相关问题