首页 » PostgreSQL/GaussDB » HighGoDB 对于number数据类型在PostgreSQL模式时无法使用索引
HighGoDB 对于number数据类型在PostgreSQL模式时无法使用索引
表是在Oracle模式下创建的,包含NUMBER
数据类型的列,在PostGreSQL模式下查询这些表时,Oracle模式下的NUMBER
类型与PG模式下的数值类型不完全匹配, 数据类型隐式转换,导致无法使用索引范围扫.
演示
Highgo 的oracle 模式
[hg@dev]$ psql highgo system -p 1521 psql (14.10) IvorySQL-pro-3.2.0 Type "help" for help. highgo=# \l List of databases Name | Owner | Encoding | Collate | Ctype | Access privileges -------------------------+-------+----------+-------------+-------------+------------------------- anbob | hg | UTF8 | en_US.UTF-8 | en_US.UTF-8 | highgo | hg | UTF8 | en_US.UTF-8 | en_US.UTF-8 | ... (9 rows) highgo=# \c anbob IvorySQL-pro-3.2.0 You are now connected to database "anbob" as user "system". ^ anbob=# create table tnum(id number,id1 int,id2 double precision,name varchar(100)); CREATE TABLE anbob=# insert into tnum select x,x,x,'anbob'||x from generate_series(1,10000) as x; INSERT 0 10000 anbob=# \d tnum Table "public.tnum" Column | Type | Collation | Nullable | Default --------+------------------+-----------+----------+--------- id | number | | | id1 | integer | | | id2 | double precision | | | name | varchar2(100) | | | anbob=# create index tnum_num on tnum(id); CREATE INDEX anbob=# create index tnum_int on tnum(id1); CREATE INDEX anbob=# create index tnum_doub on tnum(id2); CREATE INDEX anbob=# vacuum analyze tnum; VACUUM anbob=# \d+ tnum Table "public.tnum" Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description --------+------------------+-----------+----------+---------+----------+-------------+--------------+------------- id | number | | | | main | | | id1 | integer | | | | plain | | | id2 | double precision | | | | plain | | | name | varchar2(100) | | | | extended | | | Indexes: "tnum_doub" btree (id2) "tnum_int" btree (id1) "tnum_num" btree (id) Access method: heap anbob=# explain analyze select * from tnum where id=1; QUERY PLAN ---------------------------------------------------------------------------------------------------------------- Index Scan using tnum_num on tnum (cost=0.29..3.30 rows=1 width=26) (actual time=0.082..0.083 rows=1 loops=1) Index Cond: (id = '1'::number) Planning Time: 0.340 ms Execution Time: 0.123 ms (4 rows) anbob=# explain analyze select * from tnum where id1=1; QUERY PLAN ---------------------------------------------------------------------------------------------------------------- Index Scan using tnum_int on tnum (cost=0.29..3.30 rows=1 width=26) (actual time=0.111..0.115 rows=1 loops=1) Index Cond: (id1 = 1) Planning Time: 0.141 ms Execution Time: 0.148 ms (4 rows) anbob=# explain analyze select * from tnum where id2=1; QUERY PLAN ----------------------------------------------------------------------------------------------------------------- Index Scan using tnum_doub on tnum (cost=0.29..3.30 rows=1 width=26) (actual time=0.070..0.072 rows=1 loops=1) Index Cond: (id2 = '1'::double precision) Planning Time: 0.179 ms Execution Time: 0.095 ms (4 rows)
注: 在oracle 模式中可以使用索引。
Highgo 的postgresql模式
[hg@dev data]$ psql -p 5866 psql (14.10) IvorySQL-pro-3.2.0 Type "help" for help. highgo=# \l List of databases Name | Owner | Encoding | Collate | Ctype | Access privileges -------------------------+-------+----------+-------------+-------------+------------------------- anbob | hg | UTF8 | en_US.UTF-8 | en_US.UTF-8 | highgo | hg | UTF8 | en_US.UTF-8 | en_US.UTF-8 | ... (9 rows) highgo=# \c anbob IvorySQL-pro-3.2.0 You are now connected to database "anbob" as user "hg". anbob=# \d+ tnum Table "public.tnum" Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description --------+------------------+-----------+----------+---------+----------+-------------+--------------+------------- id | number | | | | main | | | id1 | integer | | | | plain | | | id2 | double precision | | | | plain | | | name | varchar2(100) | | | | extended | | | Indexes: "tnum_doub" btree (id2) "tnum_int" btree (id1) "tnum_num" btree (id) Access method: heap anbob=# explain analyze select * from tnum where id=1; QUERY PLAN -------------------------------------------------------------------------------------------------- Seq Scan on tnum (cost=0.00..234.00 rows=50 width=26) (actual time=0.025..3.695 rows=1 loops=1) Filter: ((id)::double precision = '1'::double precision) <<<<<<<< !!!! number type never use indexes Rows Removed by Filter: 9999 Planning Time: 0.338 ms Execution Time: 3.775 ms (5 rows) anbob=# explain analyze select * from tnum where id1=1; QUERY PLAN ---------------------------------------------------------------------------------------------------------------- Index Scan using tnum_int on tnum (cost=0.29..3.30 rows=1 width=26) (actual time=0.034..0.038 rows=1 loops=1) Index Cond: (id1 = 1) Planning Time: 0.136 ms Execution Time: 0.071 ms (4 rows) anbob=# explain analyze select * from tnum where id2=1; QUERY PLAN ----------------------------------------------------------------------------------------------------------------- Index Scan using tnum_doub on tnum (cost=0.29..3.30 rows=1 width=26) (actual time=0.012..0.013 rows=1 loops=1) Index Cond: (id2 = '1'::double precision) Planning Time: 0.165 ms Execution Time: 0.036 ms (4 rows) anbob=#
解决方案
1,创建函数索引
anbob=# create index idx_tnum_id_cast on tnum ((id::int)); CREATE INDEX anbob=# explain analyze select * from tnum where id=1; QUERY PLAN -------------------------------------------------------------------------------------------------- Seq Scan on tnum (cost=0.00..234.00 rows=50 width=26) (actual time=0.014..3.431 rows=1 loops=1) Filter: ((id)::double precision = '1'::double precision) Rows Removed by Filter: 9999 Planning Time: 0.400 ms Execution Time: 3.482 ms (5 rows) anbob=# explain analyze select * from tnum where id::int=1; QUERY PLAN -------------------------------------------------------------------------------------------------------------------------- Bitmap Heap Scan on tnum (cost=2.17..48.14 rows=50 width=26) (actual time=0.069..0.071 rows=1 loops=1) Recheck Cond: ((id)::integer = 1) Heap Blocks: exact=1 -> Bitmap Index Scan on idx_tnum_id_cast (cost=0.00..2.16 rows=50 width=0) (actual time=0.065..0.065 rows=1 loops=1) Index Cond: ((id)::integer = 1) Planning Time: 0.113 ms Execution Time: 0.125 ms (7 rows) anbob=# vacuum analyze tnum; VACUUM anbob=# explain analyze select * from tnum where id::int=1; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------ Index Scan using idx_tnum_id_cast on tnum (cost=0.29..3.30 rows=1 width=26) (actual time=0.008..0.010 rows=1 loops=1) Index Cond: ((id)::integer = 1) Planning Time: 0.223 ms Execution Time: 0.058 ms (4 rows)
总结:
尽量在同一个模式下创建和查询表,避免跨模式操作导致的数据类型问题,当表中使用了Oracle兼容的NUMBER数据类型时,强烈建议统一使用Oracle模式进行数据库连接和操作,在PG模式下查询包含NUMBER类型列的表时,会发生隐式类型转换,这种转换会导致查询优化器无法有效利用列上的索引,特别是影响范围扫描等高效查询方式,对于不需要Oracle特殊功能的场景,可考虑使用PostgreSQL原生数据类型如INT、BIGINT或NUMERIC替代NUMBER类型,这些类型在PG模式下能获得更好的兼容性和性能表现, 或如上创建函数索引。
目前这篇文章还没有评论(Rss)