Linux,  PostgreSQL

记录一则PostgreSQL数据库主键索引不生效的案例

一 背景说明

一则生产环境的慢SQL,发现日志表上没有任何索引,且数据量也不小,300多万条记录,走的全表扫描的执行计划,通过主键id查询数据耗时4秒多。

数据库是PostgreSQL 9.6,运行在CentOS 7.6的系统上,48颗 CPU、内存64GB。

[root@primarydb ~]# cat /etc/redhat-release 
CentOS Linux release 7.6.1810 (Core) 
[root@primarydb ~]# free -m
              total        used        free      shared  buff/cache   available
Mem:          63883        5077        3665       19767       55141       38095
Swap:         16379         843       15536
[root@primarydb ~]# su - postgres
Last login: Sat May  7 08:42:26 CST 2022 on pts/2
[postgres@primarydb ~]$ psql 
psql (9.6.21)
Type "help" for help.
​
postgres=# select version();
                                                  version                                                  
-----------------------------------------------------------------------------------------------------------
 PostgreSQL 9.6.21 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44), 64-bit
(1 row)
​
postgres=# 

二处理和分析步骤

1 查看现有SQL执行计划

fdp_image_center=> explain analyze SELECT id,receive_source,receive_data,receive_api,receive_dubbo_bean,receive_dubbo_method,deal_status,del_status,failure_code,
 failure_reason,remark,create_ts,create_user_id,update_ts,update_user_id FROM t_fdp_mgc_api_receive_log WHERE id='1G2AFM2704EG6815C0C000003E3F1006';
                                                           QUERY PLAN                                                           
--------------------------------------------------------------------------------------------------------------------------------
 Seq Scan on t_fdp_mgc_api_receive_log  (cost=0.00..672426.96 rows=1 width=867) (actual time=1844.985..4114.065 rows=1 loops=1)
   Filter: (id = '1G2AFM2704EG6815C0C000003E3F1006'::bpchar)
   Rows Removed by Filter: 3889740
 Planning time: 0.126 ms
 Execution time: 4114.110 ms
(5 rows)
​
Time: 4115.282 ms
fdp_image_center=>

2 查看表结构

fdp_image_center=> \d t_fdp_mgc_api_receive_log 
                  Table "public.t_fdp_mgc_api_receive_log"
        Column        |              Type              |      Modifiers      
----------------------+--------------------------------+---------------------
 id                   | character(32)                  | not null
 receive_source       | character varying              | not null
 receive_data         | text                           | 
 receive_api          | text                           | 
 receive_dubbo_bean   | character varying              | 
 receive_dubbo_method | character varying              | 
 deal_status          | character(1)                   | default '0'::bpchar
 del_status           | character(1)                   | default '0'::bpchar
 failure_code         | character varying              | 
 failure_reason       | character varying              | 
 remark               | character varying              | 
 create_ts            | timestamp(6) without time zone | 
 create_user_id       | character(32)                  | 
 update_ts            | timestamp(6) without time zone | 
 update_user_id       | character(32)                  | 
​
fdp_image_center=> \dt+ t_fdp_mgc_api_receive_log 
                                           List of relations
 Schema |           Name            | Type  |      Owner       |  Size   |         Description         
--------+---------------------------+-------+------------------+---------+-----------------------------
 public | t_fdp_mgc_api_receive_log | table | fdp_image_center | 4899 MB | 影像中心_接口数据接收日志表
(1 row)
​
fdp_image_center=> select count(*) from t_fdp_mgc_api_receive_log;
  count  
---------
 3889746
(1 row)
​
Time: 2578.878 ms
fdp_image_center=>

目标表上没有任何索引,数据量3889746,表大小4899 MB。

3 添加主键index

fdp_image_center=> alter table t_fdp_mgc_api_receive_log add primary key(id);
ALTER TABLE
fdp_image_center=> \d t_fdp_mgc_api_receive_log
                  Table "public.t_fdp_mgc_api_receive_log"
        Column        |              Type              |      Modifiers      
----------------------+--------------------------------+---------------------
 id                   | character(32)                  | not null
 receive_source       | character varying              | not null
 receive_data         | text                           | 
 receive_api          | text                           | 
 receive_dubbo_bean   | character varying              | 
 receive_dubbo_method | character varying              | 
 deal_status          | character(1)                   | default '0'::bpchar
 del_status           | character(1)                   | default '0'::bpchar
 failure_code         | character varying              | 
 failure_reason       | character varying              | 
 remark               | character varying              | 
 create_ts            | timestamp(6) without time zone | 
 create_user_id       | character(32)                  | 
 update_ts            | timestamp(6) without time zone | 
 update_user_id       | character(32)                  | 
Indexes:
    "t_fdp_mgc_api_receive_log_pkey" PRIMARY KEY, btree (id)
​
fdp_image_center=> explain analyze SELECT id,receive_source,receive_data,receive_api,receive_dubbo_bean,receive_dubbo_method,deal_status,del_status,failure_code,
 failure_reason,remark,create_ts,create_user_id,update_ts,update_user_id FROM t_fdp_mgc_api_receive_log WHERE id='1G2AFM2704EG6815C0C000003E3F1006';
                                                           QUERY PLAN                                                           
--------------------------------------------------------------------------------------------------------------------------------
 Seq Scan on t_fdp_mgc_api_receive_log  (cost=0.00..672426.96 rows=1 width=867) (actual time=1844.985..4114.065 rows=1 loops=1)
   Filter: (id = '1G2AFM2704EG6815C0C000003E3F1006'::bpchar)
   Rows Removed by Filter: 3889740
 Planning time: 0.126 ms
 Execution time: 4114.110 ms
(5 rows)
​
Time: 4115.282 ms
fdp_image_center=>

添加主键index之后,发现SQL依然走的是全表扫描,主键index不生效。

4 收集表统计信息

fdp_image_center=> analyze verbose t_fdp_mgc_api_receive_log;
INFO:  analyzing "public.t_fdp_mgc_api_receive_log"
INFO:  "t_fdp_mgc_api_receive_log": scanned 30000 of 623803 pages, containing 187804 live rows and 2128 dead rows; 30000 rows in sample, 3905090 estimated total rows
ANALYZE
Time: 2950.674 ms
fdp_image_center=> explain analyze SELECT id FROM t_fdp_mgc_api_receive_log WHERE id='1G2AFM2704EG6815C0C000003E3F1006';
                                                          QUERY PLAN                                                           
-------------------------------------------------------------------------------------------------------------------------------
 Seq Scan on t_fdp_mgc_api_receive_log  (cost=0.00..672616.62 rows=1 width=33) (actual time=3195.233..4508.299 rows=1 loops=1)
   Filter: (id = '1G2AFM2704EG6815C0C000003E3F1006'::bpchar)
   Rows Removed by Filter: 3889762
 Planning time: 0.357 ms
 Execution time: 4508.325 ms
(5 rows)
​
Time: 4509.674 ms
fdp_image_center=> 

收集完统计信息之后,执行计划依然是全表扫描。

到这里,内心感到纳闷儿,咋回事儿,主键索引不生效,更新表统计信息之后,依然不奏效。

5 重建主键约束

fdp_image_center=> alter table t_fdp_mgc_api_receive_log  drop constraint  t_fdp_mgc_api_receive_log_pkey ;
ALTER TABLE
Time: 1381.749 ms
fdp_image_center=> \d t_fdp_mgc_api_receive_log
                  Table "public.t_fdp_mgc_api_receive_log"
        Column        |              Type              |      Modifiers      
----------------------+--------------------------------+---------------------
 id                   | character(32)                  | not null
 receive_source       | character varying              | not null
 receive_data         | text                           | 
 receive_api          | text                           | 
 receive_dubbo_bean   | character varying              | 
 receive_dubbo_method | character varying              | 
 deal_status          | character(1)                   | default '0'::bpchar
 del_status           | character(1)                   | default '0'::bpchar
 failure_code         | character varying              | 
 failure_reason       | character varying              | 
 remark               | character varying              | 
 create_ts            | timestamp(6) without time zone | 
 create_user_id       | character(32)                  | 
 update_ts            | timestamp(6) without time zone | 
 update_user_id       | character(32)                  | 
​
fdp_image_center=> alter table t_fdp_mgc_api_receive_log add constraint unique_id primary key(id);
ALTER TABLE
Time: 36688.809 ms
fdp_image_center=> \d t_fdp_mgc_api_receive_log
                  Table "public.t_fdp_mgc_api_receive_log"
        Column        |              Type              |      Modifiers      
----------------------+--------------------------------+---------------------
 id                   | character(32)                  | not null
 receive_source       | character varying              | not null
 receive_data         | text                           | 
 receive_api          | text                           | 
 receive_dubbo_bean   | character varying              | 
 receive_dubbo_method | character varying              | 
 deal_status          | character(1)                   | default '0'::bpchar
 del_status           | character(1)                   | default '0'::bpchar
 failure_code         | character varying              | 
 failure_reason       | character varying              | 
 remark               | character varying              | 
 create_ts            | timestamp(6) without time zone | 
 create_user_id       | character(32)                  | 
 update_ts            | timestamp(6) without time zone | 
 update_user_id       | character(32)                  | 
Indexes:
    "unique_id" PRIMARY KEY, btree (id)
​
fdp_image_center=> vacuum freeze verbose ANALYZE  t_fdp_mgc_api_receive_log;
INFO:  vacuuming "public.t_fdp_mgc_api_receive_log"
INFO:  scanned index "unique_id" to remove 43239 row versions
DETAIL:  CPU 0.09s/0.26u sec elapsed 0.35 sec
INFO:  "t_fdp_mgc_api_receive_log": removed 43239 row versions in 43234 pages
DETAIL:  CPU 1.11s/0.54u sec elapsed 8.53 sec
INFO:  index "unique_id" now contains 3890163 row versions in 28045 pages
DETAIL:  0 index row versions were removed.
0 index pages have been deleted, 0 are currently reusable.
CPU 0.00s/0.00u sec elapsed 0.00 sec.
INFO:  "t_fdp_mgc_api_receive_log": found 301 removable, 3138172 nonremovable row versions in 527811 out of 623803 pages
DETAIL:  383 dead row versions cannot be removed yet.
There were 220507 unused item pointers.
Skipped 1 page due to buffer pins.
0 pages are entirely empty.
CPU 9.39s/5.67u sec elapsed 62.76 sec.
INFO:  vacuuming "pg_toast.pg_toast_51870"
INFO:  scanned index "pg_toast_51870_index" to remove 23 row versions
DETAIL:  CPU 0.00s/0.00u sec elapsed 0.57 sec
INFO:  "pg_toast_51870": removed 23 row versions in 10 pages
DETAIL:  CPU 0.00s/0.00u sec elapsed 0.00 sec
INFO:  index "pg_toast_51870_index" now contains 14774 row versions in 43 pages
DETAIL:  23 index row versions were removed.
0 index pages have been deleted, 0 are currently reusable.
CPU 0.00s/0.00u sec elapsed 0.00 sec.
INFO:  "pg_toast_51870": found 7 removable, 14774 nonremovable row versions in 3008 out of 3008 pages
DETAIL:  0 dead row versions cannot be removed yet.
There were 0 unused item pointers.
Skipped 0 pages due to buffer pins.
0 pages are entirely empty.
CPU 0.12s/0.05u sec elapsed 7.12 sec.
INFO:  analyzing "public.t_fdp_mgc_api_receive_log"
INFO:  "t_fdp_mgc_api_receive_log": scanned 30000 of 623803 pages, containing 187359 live rows and 14 dead rows; 30000 rows in sample, 3895837 estimated total rows
VACUUM
Time: 73112.829 ms
fdp_image_center=> explain analyze SELECT id,receive_source,receive_data,receive_api,receive_dubbo_bean,receive_dubbo_method,deal_status,del_status,failure_code,
 failure_reason,remark,create_ts,create_user_id,update_ts,update_user_id FROM t_fdp_mgc_api_receive_log WHERE id='1G2AFM2704EG6815C0C000003E3F1006';
                                                           QUERY PLAN                                                           
--------------------------------------------------------------------------------------------------------------------------------
 Seq Scan on t_fdp_mgc_api_receive_log  (cost=0.00..672500.96 rows=1 width=869) (actual time=2505.320..4352.022 rows=1 loops=1)
   Filter: (id = '1G2AFM2704EG6815C0C000003E3F1006'::bpchar)
   Rows Removed by Filter: 3889888
 Planning time: 0.541 ms
 Execution time: 4352.068 ms
(5 rows)
​
Time: 4353.649 ms
fdp_image_center=> 

此时的我,内心开始凌乱….一通操作,开始怀疑主键约束是不是真的创建了index?重建主键约束,还是不生效….

6 手工添加btree index

fdp_image_center=> create index CONCURRENTLY idx_fdp_mgc_api_receive_log_id on t_fdp_mgc_api_receive_log(id);
CREATE INDEX
Time: 39576.585 ms
fdp_image_center=> \d t_fdp_mgc_api_receive_log
                  Table "public.t_fdp_mgc_api_receive_log"
        Column        |              Type              |      Modifiers      
----------------------+--------------------------------+---------------------
 id                   | character(32)                  | not null
 receive_source       | character varying              | not null
 receive_data         | text                           | 
 receive_api          | text                           | 
 receive_dubbo_bean   | character varying              | 
 receive_dubbo_method | character varying              | 
 deal_status          | character(1)                   | default '0'::bpchar
 del_status           | character(1)                   | default '0'::bpchar
 failure_code         | character varying              | 
 failure_reason       | character varying              | 
 remark               | character varying              | 
 create_ts            | timestamp(6) without time zone | 
 create_user_id       | character(32)                  | 
 update_ts            | timestamp(6) without time zone | 
 update_user_id       | character(32)                  | 
Indexes:
    "unique_id" PRIMARY KEY, btree (id)
    "idx_fdp_mgc_api_receive_log_id" btree (id)
​
fdp_image_center=> explain analyze SELECT id FROM t_fdp_mgc_api_receive_log WHERE id='1G2AFM2704EG6815C0C000003E3F1006';
                                                                           QUERY PLAN                                                                           
----------------------------------------------------------------------------------------------------------------------------------------------------------------
 Index Only Scan using idx_fdp_mgc_api_receive_log_id on t_fdp_mgc_api_receive_log  (cost=0.56..8.57 rows=1 width=33) (actual time=0.070..0.071 rows=1 loops=1)
   Index Cond: (id = '1G2AFM2704EG6815C0C000003E3F1006'::bpchar)
   Heap Fetches: 0
 Planning time: 0.297 ms
 Execution time: 0.099 ms
(5 rows)
​
Time: 1.064 ms
fdp_image_center=>

啥情况?通过添加主键约束,进而隐式创建的主键index不生效,反而我手工创建的一个普通btree index却生效了。

7 复盘index信息

fdp_image_center=> select tablename,indexname,indexdef from pg_indexes where tablename='t_fdp_mgc_api_receive_log';
         tablename         |           indexname            |                                             indexdef                                             
---------------------------+--------------------------------+--------------------------------------------------------------------------------------------------
 t_fdp_mgc_api_receive_log | unique_id                      | CREATE UNIQUE INDEX unique_id ON public.t_fdp_mgc_api_receive_log USING btree (id)
 t_fdp_mgc_api_receive_log | idx_fdp_mgc_api_receive_log_id | CREATE INDEX idx_fdp_mgc_api_receive_log_id ON public.t_fdp_mgc_api_receive_log USING btree (id)
(2 rows)
​
Time: 15.095 ms
fdp_image_center=> 

8 想重现该现象

把该表导出来,然后导入到另外一个库上,想看看该情况是否会重现?

导出表:
 pg_dump -h localhost -p 5432 -d fdp_image_center -U fdp_image_center -t t_fdp_mgc_api_receive_log -f t_fdp_mgc_api_receive_log.dmp
删除该表的dump文件里的已有的2个index:vi t_fdp_mgc_api_receive_log.dmp 删掉index信息,保存退出。
新库导入表:
bill_fmt=> \i t_fdp_mgc_api_receive_log.dmp 
CREATE TABLE
psql:t_fdp_mgc_api_receive_log.dmp:25: ERROR:  must be member of role "fdp_image_center"
COMMENT
COMMENT
COMMENT
COMMENT
COMMENT
COMMENT
COMMENT
COMMENT
COMMENT
COMMENT
COMMENT
COMMENT
COMMENT
COMMENT
COMMENT
COMMENT
COPY 3915872
bill_fmt=> \d t_fdp_mgc_api_receive_log 
                  Table "public.t_fdp_mgc_api_receive_log"
        Column        |              Type              |      Modifiers      
----------------------+--------------------------------+---------------------
 id                   | character(32)                  | not null
 receive_source       | character varying              | not null
 receive_data         | text                           | 
 receive_api          | text                           | 
 receive_dubbo_bean   | character varying              | 
 receive_dubbo_method | character varying              | 
 deal_status          | character(1)                   | default '0'::bpchar
 del_status           | character(1)                   | default '0'::bpchar
 failure_code         | character varying              | 
 failure_reason       | character varying              | 
 remark               | character varying              | 
 create_ts            | timestamp(6) without time zone | 
 create_user_id       | character(32)                  | 
 update_ts            | timestamp(6) without time zone | 
 update_user_id       | character(32)                  | 
​
bill_fmt=> \dt+ t_fdp_mgc_api_receive_log 
                                       List of relations
 Schema |           Name            | Type  |  Owner   |  Size   |         Description         
--------+---------------------------+-------+----------+---------+-----------------------------
 public | t_fdp_mgc_api_receive_log | table | bill_fmt | 3396 MB | 影像中心_接口数据接收日志表
(1 row)
​
bill_fmt=>
查看执行计划:
bill_fmt=> explain analyze SELECT id,receive_source,receive_data,receive_api,receive_dubbo_bean,receive_dubbo_method,deal_status,del_status,failure_code,
 failure_reason,remark,create_ts,create_user_id,update_ts,update_user_id FROM t_fdp_mgc_api_receive_log WHERE id='1G2AFM2704EG6815C0C000003E3F1006';
                                                          QUERY PLAN                                                           
-------------------------------------------------------------------------------------------------------------------------------
 Seq Scan on t_fdp_mgc_api_receive_log  (cost=0.00..480472.40 rows=1 width=869) (actual time=881.723..6629.848 rows=1 loops=1)
   Filter: (id = '1G2AFM2704EG6815C0C000003E3F1006'::bpchar)
   Rows Removed by Filter: 3915871
 Planning time: 0.095 ms
 Execution time: 6629.884 ms
(5 rows)
​
bill_fmt=> 
添加主键约束:
bill_fmt=> alter table t_fdp_mgc_api_receive_log add  primary key(id);
ALTER TABLE
bill_fmt=> \d t_fdp_mgc_api_receive_log 
                  Table "public.t_fdp_mgc_api_receive_log"
        Column        |              Type              |      Modifiers      
----------------------+--------------------------------+---------------------
 id                   | character(32)                  | not null
 receive_source       | character varying              | not null
 receive_data         | text                           | 
 receive_api          | text                           | 
 receive_dubbo_bean   | character varying              | 
 receive_dubbo_method | character varying              | 
 deal_status          | character(1)                   | default '0'::bpchar
 del_status           | character(1)                   | default '0'::bpchar
 failure_code         | character varying              | 
 failure_reason       | character varying              | 
 remark               | character varying              | 
 create_ts            | timestamp(6) without time zone | 
 create_user_id       | character(32)                  | 
 update_ts            | timestamp(6) without time zone | 
 update_user_id       | character(32)                  | 
Indexes:
    "t_fdp_mgc_api_receive_log_pkey" PRIMARY KEY, btree (id)
​
bill_fmt=> explain analyze SELECT id,receive_source,receive_data,receive_api,receive_dubbo_bean,receive_dubbo_method,deal_status,del_status,failure_code,
 failure_reason,remark,create_ts,create_user_id,update_ts,update_user_id FROM t_fdp_mgc_api_receive_log WHERE id='1G2AFM2704EG6815C0C000003E3F1006';
                                                                         QUERY PLAN                                                                         
------------------------------------------------------------------------------------------------------------------------------------------------------------
 Index Scan using t_fdp_mgc_api_receive_log_pkey on t_fdp_mgc_api_receive_log  (cost=0.56..8.57 rows=1 width=869) (actual time=0.167..0.168 rows=1 loops=1)
   Index Cond: (id = '1G2AFM2704EG6815C0C000003E3F1006'::bpchar)
 Planning time: 0.370 ms
 Execution time: 0.206 ms
(4 rows)
​
bill_fmt=> 

这时,想重现该现象,发现添加主键约束之后,SQL执行计划立即改善。

手工创建btree index:
bill_fmt=> create index CONCURRENTLY idx_t_fdp_mgc_api_receive_log_id on t_fdp_mgc_api_receive_log(id);
CREATE INDEX
bill_fmt=> \d t_fdp_mgc_api_receive_log
                  Table "public.t_fdp_mgc_api_receive_log"
        Column        |              Type              |      Modifiers      
----------------------+--------------------------------+---------------------
 id                   | character(32)                  | not null
 receive_source       | character varying              | not null
 receive_data         | text                           | 
 receive_api          | text                           | 
 receive_dubbo_bean   | character varying              | 
 receive_dubbo_method | character varying              | 
 deal_status          | character(1)                   | default '0'::bpchar
 del_status           | character(1)                   | default '0'::bpchar
 failure_code         | character varying              | 
 failure_reason       | character varying              | 
 remark               | character varying              | 
 create_ts            | timestamp(6) without time zone | 
 create_user_id       | character(32)                  | 
 update_ts            | timestamp(6) without time zone | 
 update_user_id       | character(32)                  | 
Indexes:
    "t_fdp_mgc_api_receive_log_pkey" PRIMARY KEY, btree (id)
    "idx_t_fdp_mgc_api_receive_log_id" btree (id)
​
bill_fmt=> explain analyze SELECT id,receive_source,receive_data,receive_api,receive_dubbo_bean,receive_dubbo_method,deal_status,del_status,failure_code,
 failure_reason,remark,create_ts,create_user_id,update_ts,update_user_id FROM t_fdp_mgc_api_receive_log WHERE id='1G2AFM2704EG6815C0C000003E3F1006';
                                                                          QUERY PLAN                                                                          
--------------------------------------------------------------------------------------------------------------------------------------------------------------
 Index Scan using idx_t_fdp_mgc_api_receive_log_id on t_fdp_mgc_api_receive_log  (cost=0.56..8.57 rows=1 width=869) (actual time=0.050..0.051 rows=1 loops=1)
   Index Cond: (id = '1G2AFM2704EG6815C0C000003E3F1006'::bpchar)
 Planning time: 0.416 ms
 Execution time: 0.105 ms
(4 rows)
​
bill_fmt=>

再看此时的执行计划,就更滑稽了,原有的主键index不走,PostgreSQL的优化器反而用了新建的btree index!

继续分析:
bill_fmt=> drop index idx_t_fdp_mgc_api_receive_log_id;
DROP INDEX
bill_fmt=> explain analyze SELECT id,receive_source,receive_data,receive_api,receive_dubbo_bean,receive_dubbo_method,deal_status,del_status,failure_code,
 failure_reason,remark,create_ts,create_user_id,update_ts,update_user_id FROM t_fdp_mgc_api_receive_log WHERE id='1G2AFM2704EG6815C0C000003E3F1006';
                                                                         QUERY PLAN                                                                         
------------------------------------------------------------------------------------------------------------------------------------------------------------
 Index Scan using t_fdp_mgc_api_receive_log_pkey on t_fdp_mgc_api_receive_log  (cost=0.56..8.57 rows=1 width=869) (actual time=0.048..0.050 rows=1 loops=1)
   Index Cond: (id = '1G2AFM2704EG6815C0C000003E3F1006'::bpchar)
 Planning time: 0.226 ms
 Execution time: 0.090 ms
(4 rows)
​
bill_fmt=> 

优化器,你也不傻呀。还是用回了主键index。

扫尾工作:

连回到原来的数据库,删掉btree index之后,优化器又识别了主键index,并且生效了。

postgres=# \c fdp_image_center fdp_image_center 
You are now connected to database "fdp_image_center" as user "fdp_image_center".
fdp_image_center=> explain analyze SELECT id,receive_source,receive_data,receive_api,receive_dubbo_bean,receive_dubbo_method,deal_status,del_status,failure_code,
 failure_reason,remark,create_ts,create_user_id,update_ts,update_user_id FROM t_fdp_mgc_api_receive_log WHERE id='1G2AFM2704EG6815C0C000003E3F1006';
                                                                          QUERY PLAN                                                                          
--------------------------------------------------------------------------------------------------------------------------------------------------------------
 Index Scan using idx_fdp_mgc_api_receive_log_id on t_fdp_mgc_api_receive_log  (cost=0.56..8.57 rows=1 width=869) (actual time=16.280..16.282 rows=1 loops=1)
   Index Cond: (id = '1G2AFM2704EG6815C0C000003E3F1006'::bpchar)
 Planning time: 83.287 ms
 Execution time: 16.397 ms
(4 rows)
​
fdp_image_center=> \d t_fdp_mgc_api_receive_log
                  Table "public.t_fdp_mgc_api_receive_log"
        Column        |              Type              |      Modifiers      
----------------------+--------------------------------+---------------------
 id                   | character(32)                  | not null
 receive_source       | character varying              | not null
 receive_data         | text                           | 
 receive_api          | text                           | 
 receive_dubbo_bean   | character varying              | 
 receive_dubbo_method | character varying              | 
 deal_status          | character(1)                   | default '0'::bpchar
 del_status           | character(1)                   | default '0'::bpchar
 failure_code         | character varying              | 
 failure_reason       | character varying              | 
 remark               | character varying              | 
 create_ts            | timestamp(6) without time zone | 
 create_user_id       | character(32)                  | 
 update_ts            | timestamp(6) without time zone | 
 update_user_id       | character(32)                  | 
Indexes:
    "unique_id" PRIMARY KEY, btree (id)
    "idx_fdp_mgc_api_receive_log_id" btree (id)
​
fdp_image_center=> drop index idx_fdp_mgc_api_receive_log_id;
DROP INDEX
fdp_image_center=> explain analyze SELECT id,receive_source,receive_data,receive_api,receive_dubbo_bean,receive_dubbo_method,deal_status,del_status,failure_code,
 failure_reason,remark,create_ts,create_user_id,update_ts,update_user_id FROM t_fdp_mgc_api_receive_log WHERE id='1G2AFM2704EG6815C0C000003E3F1006';
                                                               QUERY PLAN                                                                
-----------------------------------------------------------------------------------------------------------------------------------------
 Index Scan using unique_id on t_fdp_mgc_api_receive_log  (cost=0.56..8.57 rows=1 width=869) (actual time=21.814..21.816 rows=1 loops=1)
   Index Cond: (id = '1G2AFM2704EG6815C0C000003E3F1006'::bpchar)
 Planning time: 0.230 ms
 Execution time: 21.852 ms
(4 rows)
​
fdp_image_center=> explain analyze SELECT id,receive_source,receive_data,receive_api,receive_dubbo_bean,receive_dubbo_method,deal_status,del_status,failure_code,
 failure_reason,remark,create_ts,create_user_id,update_ts,update_user_id FROM t_fdp_mgc_api_receive_log WHERE id='1G2AFM2704EG6815C0C000003E3F1006';
                                                              QUERY PLAN                                                               
---------------------------------------------------------------------------------------------------------------------------------------
 Index Scan using unique_id on t_fdp_mgc_api_receive_log  (cost=0.56..8.57 rows=1 width=869) (actual time=0.056..0.057 rows=1 loops=1)
   Index Cond: (id = '1G2AFM2704EG6815C0C000003E3F1006'::bpchar)
 Planning time: 0.135 ms
 Execution time: 0.095 ms
(4 rows)
​
fdp_image_center=> 

三小结

1 PostgreSQL数据库给表添加主键约束时,会自动在该表上创建主键index。这一点儿跟Oracle数据库不同,Oracle里约束是约束,index是index;

2 PostgreSQL数据库给表添加了主键约束,进而隐式的创建了主键index,可是,该index不生效,更新了表统计信息之后,主键index依然不生效;不得已手工添加了btree index反而生效,纳闷儿?

3 同一个数据库服务器,换1个数据库,重现该现象时,一旦添加主键约束,优化器立即识别了主键index,并且生效了,更纳闷儿?

4 暂且把这个问题现象记录下来,留作以后慢慢再复盘吧。我自己都解释不了,说不定以后复盘时会有更新的收获和认知。

留言