首页 » 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)

我要评论