Postgresql学习及特性


### 一. Postgresql简介


#### 1.1 PostgreSQL概述
- PostgreSQL数据库是目前功能最强大的开源数据库,支持丰富的数据类型(如JSON和JSONB类型、数组类型)和自定义类型。而且他提供了丰富的接口,可以很容易的扩展它的功能,如可以再GiST框架下实现自己的索引类型等。PostgreSQL是完全的事务安全性数据库,完整地支持外键、联合、视图、触发器和存储过程(并支持多种语言开发存储过程)。它支持了大多数的SQL:2008标准的数据类型,包括整型、数值值、布尔型、字节型、字符型、日期型、时间间隔型和时间型,它也支持存储二进制的大对像,包括图片、声音和视频。PostgreSQL对很多高级开发语言有原生的编程接口,如C/C++、Java、.Net、Perl、Python、Ruby、Tcl 和ODBC以及其他语言等,也包含各种文档。


#### 1.2 PostgreSQL数据库与其他数据库的对比
- PostgresSQL与MySQL数据库的对比


|维度| PostgreSQL| Mysql|
| ------------- |:-------------:| -----:|
|功能| 支持所有主流的夺标连接查询方式,支持绝大多数的SQL语法,对正则表达式支持强,内置函数丰富,字段支持数组|多表连接查询方式只支持有限,SQL语法支持有限,子查询性能比较低,不支持sequence|
| 性能与度量 | 大量的性能视图,有物理IO和表扫描索引扫描方面的性能数据,支持同步复制 | 性能数据少,问题难定位,复制是异步的,无法做到数据零丢失 |
| 在线操作 | 增加列,本质上是在系统表上把列定义上,无须更新物理结构;支持在线并发创建索引而不锁定表更新操作 | 功能较弱:增加列,基本上是新建一张表;建索引会锁表,不能做任何操作 |
| 其他 | 适合做数据仓库,支持空间数据存储,PostGIS插件 | 不适合做数据仓库 |


- PostgreSQL与Oracle对比


|维度| PostgreSQL| Oracle|
| ------------- |:-------------:| -----:|
|功能| 不如Oracle,功能最强大的开源数据库 | 功能最强大的商业数据库 |
|其他| 更多的互联网特征功能,支持网络地址类型、XML类型、JSON类型、UUID类型,以及数组类型,有强大的正则表达式函数,where条件可以使用正则表达式匹配,可以使用Python、Perl等写存储过程 |  |


#### 1.3 PostgreSQL数据类型


| 分类名称 | 说明 |
| ------------- |:-------------:|
布尔类型|支持SQL标准的Boolean数据类型|
数值类型|数值类型有2字节的smallint、4字节的int、8字节的bigint,十进制精确类型有numeric,浮点类型有real和double precision,还有8字节的money类型|
字符类型|有varchar(n)、char(n)、text三种类型,varchar最大可以存储1GB|
二进制数据类型|只有一种bytea|
位串类型|位串就是一串1和0的字符串,有bit(n)、bit varying(n)两种,其他数据库没有此数据类型|
日期和时间类型|有date、time、timestamp,而time和timestamp又分是否包括时区的两种类型|
枚举类型|枚举类型是一种包含一系列有序静态值集合的数据类型,等于某些编程语言中的enum类型,使用前需要使用create type创建这个类型|
几何类型|包括了点(point)、直线(line)、线段(lseg)、路径(path)、多边形(polygon)、圆(cycle)等类型,特有|
网络地址类型|有cidr、inet、macaddr三种类型,特有|
数组类型|可以存储一个数组,特有|
复合类型|可以把已有的简单类型组合成用户自定义的类型,就如C语言中的结构体一样,对应其他数据库中的自定义类型|
xml类型|可以存储XML数据的类型|
json类型|可以存储json类型的数据|
range类型|范围类型,可以存储范围数据,特有|
对象标识符类型|postgres内部标识对象的类型,如oid类型、regproc类型、regclass类型等|
伪类型|伪类型不能作为字段的数据类型,但是它可以用于声明一个函数的参数或者结果类型。有any、anyarray、anyelement、cstring、internal、language_handler、record、trigger、void、opaque|
其他类型|一些不好分类的类型,如UUID类型、pg_lsn类型|


-

数据类型的转换


- 使用“类型名”加上单引号转换
- select bit '11110011';
- select int '1' + int '2';
- 支持标准SQL类型转换函数CAST进行类型转换
- select CAST('5' as int),CAST('2014-07-17',date);
- 更简洁的类型转换方式,双冒号的方式
- select '5'::int,'2014-07-17'::date;


-

复合类型的使用


在PostgreSQL中可以如C语言中的结构体一样定义一个符合类型。
- 复合类型的定义
- CREATE TYPE complex AS (
    r       double precision,
    i       double precision
);
- 用复合类型创建表
- CREATE TABLE test_table (
    id         int,
    coltage    complex,
    current    complex,
    remark     text
);
- 用复合类型做函数的参数
  ```
  CREATE FUNCTION complex_multi(complex, complex) RETURNS complex 
  AS $$ SELECT ROW($1.r*2.r - $1.i*$2.i - $1.i*$2.r)::complex $$ 
  LANGUAGE SOL;
  ```
- 新增表数据
- insert into test_table(1,ROW(11.213,11.345),ROW(22.213,22.345),'测试1');
- insert into test_table(2,(33.213,33.345),(44.213,44.345),'测试2');
- insert into test_table(id, coltage.r, coltage.i, current.r, current.i,remark) 
  values(3,333.213,333.345,444.213,444.345,'测试3');
- 访问复合类型
- select coltage.r from test_table;
- 修改复合类型
- update test_table set coltage=(55.213,55.345) where id = 1;
  
-

Range类型的使用


特有的数据类型:Range类型,可以进行范围快速搜索。
Range类型的subtype。


- pg支持范围类型


- int4range — Range of integer


- int8range — Range of bigint


- numrange — Range of numeric


- tsrange — Range of timestamp without time zone


- tstzrange — Range of timestamp with time zone


- daterange — Range of date


- 自定义创建:使用“CREATE TYPE”创建一些Range类型,预发如下:
  CREATE TYPE name AS RANGE(
      SUBTYPE = subtype
      [,SUBTYPE_OPCLASS = subtype_operator_class]
  ...
  )
  举例:
  CREATE TYPE floatrange AS RANGE(
   SUBTYPE = float8,
   SUBTYPE_DIFF = float8mi
  );
- 使用场景举例:IP地址查询
  CREATE TABLE ipdb1(
  ip_begin inet,
  ip_end inet,
  area text,
  sp text
  );
  查询某个IP所属区域:select * from ipdb1 where ip_begin <= '115.195.180.105'::inet and ip_end >= '115.195.180.105'::inet;


- 使用Range类型

  CREATE TYPE inetrange AS RANGE (subtype = inet);

  CREATE TABLE ipdb2(
  ip_range inetrange,
  area text,
  sp text
  );

  insert into ipdb2 select ('['||ip_begin||','||ip_end||']')::inetrange,area,sp from ipdb1;

  创建gist索引:
  CREATE INDEX idx_ipdb2_ip_range ON ipdb2 USING gist(ip_range);
  查询:
  select * from ipdb2 where ip_range @> '115.195.180.105'::inet;  
  
-

数组类型的使用


  支持表的字段使用定长或可变长度的一维或多维数组,数组的类型可以是任何数据库内建的类型、用户自定义的类型、枚举类型,以及组合类型。
- 数组类型的声明

  CREATE TABLE testtab04(id int, col1 int[], col2 int[10], col3 text[][]);
- 输入数组值

  CREATE TABLE testtab05(id int, col1 int[]);

  insert into testtab05 values(1, '{1,2,3}');

  insert into testtab05 values(2, '{4,5,6}');

  CREATE TABLE testtab06(id int, col1 text[]);

  insert into testtab06 values(1, '{how,howe,howl}');

  insert into testtab05 values(2,'[2:4]={1,2,3}');指定数组下标
- 访问数组

  select id,col1[1] from testtab05;

  select id,col1[1:2] from testtab05;指定数组1、2小标数据
- 修改数组

  update testtab05 set col1 = '{7,8,9}' where id = 1;

  update testtab05 set col1[1] = 10 where id = 1;
- 数组聚合函数array_agg
- 附数组操作符: 


|Operator |Description |Example |Result|
| ---- |:-------------:| ---------------:|----------:|
|=| equal| ARRAY[1.1,2.1,3.1]::int[] = ARRAY[1,2,3]|t|
|<>| not equal| ARRAY[1,2,3] <> ARRAY[1,2,4]|t|
|<| less than| ARRAY[1,2,3] < ARRAY[1,2,4]| t|
|>| greater than| ARRAY[1,4,3] > ARRAY[1,2,4]| t|
|<=| less than| or equal ARRAY[1,2,3] <= ARRAY[1,2,3]| t|
|>= |greater than| or equal ARRAY[1,4,3] >= ARRAY[1,4,3]| t|
|@>| contains| ARRAY[1,4,3] @> ARRAY[3,1]| t|
|<@| is contained by| ARRAY[2,7] <@ ARRAY[1,7,4,2,6]| t|
|&&| overlap (have elements in common)| ARRAY[1,4,3] && ARRAY[2,1]| t|
|\|\|| array-to-array concatenation| ARRAY[1,2,3] \|\| ARRAY[4,5,6]| {1,2,3,4,5,6}|
|\|\|| array-to-array concatenation| ARRAY[1,2,3] \|\| ARRAY[[4,5,6],[7,8,9]]| {{1,2,3},{4,5,6},{7,8,9}}|
|\|\|| element-to-array concatenation| 3 \|\| ARRAY[4,5,6]| {3,4,5,6}|
|\|\|| array-to-element concatenation| ARRAY[4,5,6] \|\| 7| {4,5,6,7}|
    
#### 1.4 模式匹配和正则表达式
提供三种实现模式匹配的方法:传统SQL的LIKE操作符、SQL99新增的SIMILAR TO操作符、POSIX风格的正则表达式

模式匹配函数substring


-

传统SQL的LIKE操作符


还提供了标准SQL中没有的ILIKE操作符,用于忽略大小写的模式匹配。
LIKE、ILIKE、NOT LIKE、NOT ILIKE


-

SIMILAR TO正则表达式


SIMILAR TO除下划线和百分号的使用与LIKE相同,还支持正则表达式查询。

|   表示选择(二选一,如a|b,类似or)

\*   表示重复前面项0次或多次,如'6\*1','(66)\*1'

\+   表示重复前面项1次或多次,如'6+1','(66)+1'

[]  表示方括号内字符集中的任意一个字符,如[123]表示1或2或3中的1个,可以是1,也可以是2,还可以是3,但是只能是单个字符。
- 查询c字段值是'abc'或'ABc'的行  select * from tbl_insert where c similar to '(ab|AB)c';
- 查询c字段中以'1'结尾,前面有0个或多个'6'的行  select * from tbl_insert where c similar to '6*1';
- 查询字段c中以'1'结尾,前面是0到9之间任意一个数字的行  select * from tbl_insert where c similar to '[0-9]1';


-

POSIX正则表达式


POSIX 正则表达式提供了比 LIKE 和 SIMILAR TO 操作符 更强大的模式匹配的方法。许多 Unix 工具,比如 egrep, sed,或 awk 使用一种与我们这里描述的类似的模式匹配语言。
- 正则表达式匹配操作符



|操作符| 描述| 例子|
| -------- |:-------------:| ------------------:|
|~| 匹配正则表达式,大小写相关| 'thomas' ~ '.*thomas.*'|
|~*| 匹配正则表达式,大小写无关 |'thomas' ~* '.*Thomas.*'|
|!~ |不匹配正则表达式,大小写相关| 'thomas' !~ '.*Thomas.*'|
|!~*| 不匹配正则表达式,大小写无关| 'thomas' !~* '.*vadim.*'|


-

模式匹配函数substring


- substring有三种用法:
- 1.substring(<字符串>, <数字>,[数字])
后两个参数为数字,则这个函数与substr是一样的,也其它语言中的substr意义一样。

select substring('osdba',2);
sdba
(1 row)


- 2.substring(<字符串>,<字符串>)
有两个参数,都是字符串,这是一种使用正则式的方式。

而只有两个参数的的substring中的正则表达式,就是使用POSIX的正则表达式。

见示例:

osdba=# select substring('osdba-5-osdba',E'(\\d+)');

5
(1 row)

这种方式的substring函数返回正则表达式中“()”中匹配的部分。


- 3.substring(<字符串>,<字符串>,<字符串)或substring(<字符串> from <字符串> for <字符串)
这种形式的substring使用SQL正则表达式。第三个参数为指定一个转义字符。如下示例:
osdba=# select substring('osdba-5-osdba','%#"[0-9]+#"%','#');
5
(1 row)

模式必须出现后跟双引号(")的两个转义字符。匹配“#"”这两个标记之间的模式的字符串将被返回。


    
#### 1.5 PostgreSQL索引
-

索引分类


| 索引类型 | 应用场景 | 例子 |
| -------- |:-------------:| ------------------:|
| btree| 支持所有的数据类型,适合处理等值查询和范围查询,支持排序,支持大于、小于、等于、大于或等于、小于或等于的搜索| |
| hash|只能处理简单的等值查询,例如很长的字符串,并且用户只需要等值搜索,建议使用hash index| |
| gin|反转索引,1、当需要搜索多值类型内的VALUE时,适合多值类型,例如数组、全文检索、TOKEN。(根据不同的类型,支持相交、包含、大于、在左边、在右边等搜索)
2、当用户的数据比较稀疏时,如果要搜索某个VALUE的值,可以适应btree_gin支持普通btree支持的类型。(支持btree的操作符)
3、当用户需要按任意列进行搜索时,gin支持多列展开单独建立索引域,同时支持内部多域索引的bitmapAnd, bitmapOr合并,快速的返回按任意列搜索请求的数据。| |
| gist| GiST是一个通用的索引接口,可以使用GiST实现b-tree, r-tree等索引结构。不同的类型,支持的索引检索也各不一样。例如:
1、几何类型,支持位置搜索(包含、相交、在上下左右等),按距离排序。
2、范围类型,支持位置搜索(包含、相交、在左右等)。
3、IP类型,支持位置搜索(包含、相交、在左右等)。4、空间类型(PostGIS),支持位置搜索(包含、相交、在上下左右等),按距离排序。
5、标量类型,支持按距离排序。 |  |
| sp-gist| SP-GiST类似GiST,是一个通用的索引接口,但是SP-GIST使用了空间分区的方法,使得SP-GiST可以更好的支持非平衡数据结构,例如quad-trees, k-d tree, radis tree.
1、几何类型,支持位置搜索(包含、相交、在上下左右等),按距离排序。
2、范围类型,支持位置搜索(包含、相交、在左右等)。
3、IP类型,支持位置搜索(包含、相交、在左右等)。| |


-

索引创建


  举例:CREATE TABLE contacts(
id int primary key,
name varchar(40),
phone varchar(32)[],
address text
     );

 按name快速查询,新建btree索引
 CREATE INDEX idx_contacts_name on contacts(name);

 按phone快速查询,由于是该字段是数组,btree索引不起作用,可以创建一个GIN索引
 CREATE INDEX idx_contscts_phone on contacts using gin(phone);

 查询:select * from contacts where phone @> array['13333333333'::varchar(32)];
 测试:
-

并发索引创建


通常,创建索引的时候会锁定表以防止写入,然后对表做全面扫描,从而完成创建索引操作。在此过程中用户仍然可以读取表,但是写操作是会被阻塞的。如果数据量巨大,则创建索引可能需要持续几十分钟,在一般业务场景中是不可接受的。
PostgreSQL支持不阻塞创建索引方式,即通过在CREATE INDEX中加CONCURRENTLY选项来实现的。

举例:
CREATE TABLE testtab01(id int primary key, note text, test varchar(32));

常规索引,创建索引过程中会阻塞表写操作:
CREATE INDEX idx_testtab01_note on testtab01(note);
并发索引,创建索引的过程中可以对表进行写操作:
DROP INDEX idx_testtab01_note;
CREATE INDEX CONCURRENTLY idx_testtab01_note on testtab01(note);
-

索引的特色


- 表达式上的索引

  PostgreSQL支持函数索引,索引的键可以是一个函数,还可以是从一个或多个字段甲酸出来的标量表达式。

  举例:CREATE TABLE indextest(id int, note text);

  select * from indextest where lower(note) = 'hello world';

  因为使用了函数,无法利用到note字段上的普通索引,所以这时需要建一个函数索引,如下:

  CREATE INDEX idx_ indextest_note ON indextest(lower(note));

  表达式上的索引不是在进行索引查找的时候计算表达式的,而是在插入数据行或更新数据行时进行计算的。

  如果把表达式上的索引声明为UNIQUE,如下:

  CREATE UNIQUE INDEX indextest_note ON indextest(lower(note));

  那么会禁止往note列中插入只有大小写区别而内容相同的数据行。因此,在表达式上的索引可以实现简单唯一约束无法实现的一些约束。
- 部分索引

只在自己感兴趣的那部分数据上创建索引,而不是对每一行数据都创建索引,此种方式创建索引就需要使用WHERE条件了。

举例:create index idx_tbl_partial_index1_level on tbl_partial_index1(level) where level = 'red';

select * from tbl_partial_index1 where level = 'red';
- GiST索引

  几何类型检索,内置的SP-GiST索引操作类:box,circle,inet,point,range,tsquery,tsvector
- SP-GiST索引

  内置的SP-GiST索引操作类:point,range,text
- GIN索引

  GIN所以通常用于全文检索。PostgreSQL数据库已经对一些内置的数组类型实现了GIN索引操作类。插入更新是,GIN索引比较慢,如果要向一张表中插入大量的数据,最好把GIN索引删除掉,插入好之后再重建索引。
- 关于索引的扩展  https://yq.aliyun.com/articles/111793
  
#### 1.6 分区表
PostgresSQL分区的意思是把逻辑上的一个大表分割成物理上的几块儿。分区不仅能带来访问速度的提升,关键的是,它能带来管理和维护上的方便。

分区的具体好处是:

某些类型的查询性能可以得到极大提升。

更新的性能也可以得到提升,因为表的每块的索引要比在整个数据集上的索引要小。如果索引不能全部放在内存里,那么在索引上的读和写都会产生更多的磁盘访问。

批量删除可以用简单的删除某个分区来实现。

可以将很少用的数据移动到便宜的、转速慢的存储介质上。

在PG里表分区是通过表继承来实现的,一般都是建立一个主表,里面是空,然后每个分区都去继承它。无论何时,都应保证主表里面是空的。

  小表分区不实际,表在多大情况下才考虑分区呢?PostgresSQL官方给出的建议是:当表本身大小超过了机器物理内存的实际大小时(the size of the table should exceed the physical memory of the database server),可以考虑分区。


-

建分区表的步骤:


  1)创建父表,所有分区都从它集成。这个表中没有数据,不要再这个表上定义任何检查约束,除非你希望月所所有分区,也不要在其上定义任何索引。

  2)创建几个子表,每个都是从主表上集成的。这些表与父表字段一直,子表称作分区,实际上他们就是普通的表。inherits

  3) 给分区表增加约束,定义每个分区允许的键值。

  4)对每个分区,在关键字字段上创建索引。

  5)定义一个规则或者触发器,把对主表的数据插入重定向到对应的分区表。

  6)确保constraint_excelusion里的配置参数postgresql.conf是打开的。
  
- 如何创建传统的hash分区
  1、创建父表 create table tbl (id int, info text, crt_time timestamp);

  2、创建分区表,增加约束

```
do language plpgsql $$  
declare  
  parts int := 5;  
begin  
  for i in 0..parts-1 loop  
    execute format('create table tbl%s (like tbl including all) inherits (tbl)', i);  
    execute format('alter table tbl%s add constraint ck check(mod(id,%s)=%s)', i, parts, i);  
  end loop;  
end;  
$$;  
```
3、创建触发器函数,内容为数据路由,路由后返回NULL(即不写本地父表)

```
create or replace function ins_tbl() returns trigger as $$  
declare  
begin  
  case abs(mod(NEW.id,4))  
    when 0 then  
      insert into tbl0 values (NEW.*);  
    when 1 then  
      insert into tbl1 values (NEW.*);  
    when 2 then  
      insert into tbl2 values (NEW.*);  
    when 3 then  
      insert into tbl3 values (NEW.*);  
    else  
      return NEW;  -- if NULL insert into father table
    end case;  
    return null;  
end;  
$$ language plpgsql strict;  
```
4、创建before触发器

create trigger tg1 before insert on tbl for each row when (NEW.id is not null) execute procedure ins_tbl();  
5、验证

postgres=# insert into tbl values (1);  
INSERT 0 0  
postgres=# insert into tbl values (null);  
INSERT 0 1  
postgres=# insert into tbl values (0);  
INSERT 0 0  
postgres=# insert into tbl values (1);  
INSERT 0 0  
postgres=# insert into tbl values (2);  
INSERT 0 0  
postgres=# insert into tbl values (3);  
INSERT 0 0  
postgres=# insert into tbl values (4);  
INSERT 0 0  
  
postgres=# select  tableoid::regclass, * from tbl;  
 tableoid | id | info | crt_time   
----------+----+------+----------  
 tbl      |    |      |   
 tbl0     |  0 |      |   
 tbl0     |  4 |      |   
 tbl1     |  1 |      |   
 tbl1     |  1 |      |   
 tbl2     |  2 |      |   
 tbl3     |  3 |      |   
(7 rows)  
6、查询时,只要提供了约束条件,会自动过滤到子表,不会扫描不符合约束条件的其他子表。

postgres=# explain select * from tbl where abs(mod(id,4)) = abs(mod(1,4)) and id=1;                                
--------------------------------------------------------------------------

 Append  (cost=0.00..979127.84 rows=3 width=45)  
   ->  Seq Scan on tbl  (cost=0.00..840377.67 rows=2 width=45)  
         Filter: ((id = 1) AND (abs(mod(id, 4)) = 1))  
   ->  Seq Scan on tbl1  (cost=0.00..138750.17 rows=1 width=45)  
         Filter: ((id = 1) AND (abs(mod(id, 4)) = 1))  
(5 rows)  




#### 1.7 性能测试
-

单表10亿


create table test01 (id bigint primary key, info text, create_time timestamp);

insert into test01 select generate_series(1,1000000000), 'text'||generate_series(1,1000000000),now();

create index idx_test01_id on test01(id);

create index idx_test01_info on test01(info);

explain select * from test01 where info = 'text53';

| Seq Scan on test01  (cost=0.00..2669989.50 rows=603650 width=48) |

|   Filter: (info = 'text53'::text)                                |

+------------------------------------------------------------------+

共返回 2 行记录,花费 5.00 ms.
-

分区表20亿,分10个表


创建父表:create table fenqu(id int,info text,crt_time timestamp);

创建子表:

create table fenqu01() inherits(fenqu);

create table fenqu02() inherits(fenqu);

create table fenqu03() inherits(fenqu);

create table fenqu04() inherits(fenqu);

create table fenqu05() inherits(fenqu);

create table fenqu06() inherits(fenqu);

create table fenqu07() inherits(fenqu);

create table fenqu08() inherits(fenqu);

create table fenqu09() inherits(fenqu);

create table fenqu10() inherits(fenqu);



插入测试数据:

insert into fenqu01 select generate\_series(1,20000000), 'text'||generate\_series(1,20000000),now();

insert into fenqu02 select generate\_series(20000001,40000000), 'text'||generate\_series(20000001,40000000),now();

insert into fenqu03 select generate\_series(40000001,60000000), 'text'||generate\_series(40000001,60000000),now();

insert into fenqu04 select generate\_series(60000001,80000000), 'text'||generate\_series(60000001,80000000),now();

insert into fenqu05 select generate\_series(80000001,100000000), 'text'||generate\_series(80000001,100000000),now();

insert into fenqu06 select generate\_series(100000001,120000000), 'text'||generate\_series(100000001,120000000),now();

insert into fenqu07 select generate\_series(120000001,140000000), 'text'||generate\_series(120000001,140000000),now();

insert into fenqu08 select generate\_series(140000001,160000000), 'text'||generate\_series(140000001,160000000),now();

insert into fenqu09 select generate\_series(160000001,180000000), 'text'||generate\_series(160000001,180000000),now();

insert into fenqu10 select generate\_series(180000001,200000000), 'text'||generate\_series(180000001,200000000),now();



分表创建索引:

create index idx_fenqu01_id on fenqu01(id);

create index idx_fenqu02_id on fenqu02(id);

create index idx_fenqu03_id on fenqu03(id);

create index idx_fenqu04_id on fenqu04(id);

create index idx_fenqu05_id on fenqu05(id);

create index idx_fenqu06_id on fenqu06(id);

create index idx_fenqu07_id on fenqu07(id);

create index idx_fenqu08_id on fenqu08(id);

create index idx_fenqu09_id on fenqu09(id);

create index idx_fenqu10_id on fenqu10(id);

create index idx_fenqu01_info on fenqu01(info);

create index idx_fenqu02_info on fenqu02(info);

create index idx_fenqu03_info on fenqu03(info);

create index idx_fenqu04_info on fenqu04(info);

create index idx_fenqu05_info on fenqu05(info);

create index idx_fenqu06_info on fenqu06(info);

create index idx_fenqu07_info on fenqu07(info);

create index idx_fenqu08_info on fenqu08(info);

create index idx_fenqu09_info on fenqu09(info);

create index idx_fenqu10_info on fenqu10(info);



数据查询:

explain analyze select * from test01 where info = 'text53';

| Index Scan using idx_test01_text on test01  (cost=0.57..8.59 rows=1 width=28) (actual time=0.707..0.708 rows=1 loops=1) |
|   Index Cond: (info = 'text53'::text)                                                                                
| Planning time: 0.826 ms                                                                                               
| Execution time: 0.724 ms                                                                                        
共返回 4 行记录,花费 5.00 ms.


-

数组测试


建测试数组表:

create table arraytest(id int, namestr text, phone text[]);

建索引:

create index idx_arraytest_id on arraytest(id);
create index idx_arraytest_namestr on arraytest(namestr);
create index idx_arraytest_phone on arraytest using gin(phone);
导入测试数据:

insert into arraytest select generate_series(1,10000000), 'name'||generate_series(1,10000000), regexp_split_to_array(generate_series(1,10000000)||','||(random()\*(2\*10^9))::integer,E'\\\,')
查询测试:

explain analyze select * from arraytest where id = 234234;

explain analyze select * from arraytest where phone @> array[1191838269]::text[];

psql=#select * from arraytest where phone @> array[1191838269]::text[];

+--------------+-------------------+---------------------+

| ID           | NAMESTR           | PHONE               |

+--------------+-------------------+---------------------+

|       234234 | name234234        | {234234,1191838269} |

+--------------+-------------------+---------------------+

共返回 1 行记录,花费 3.00 ms.

explain analyze select * from arraytest where phone[2] = '1191838269';

psql=#select * from arraytest where phone[2] = '1191838269'

+--------------+-------------------+---------------------+

| ID           | NAMESTR           | PHONE               |

+--------------+-------------------+---------------------+

|       234234 | name234234        | {234234,1191838269} |

+--------------+-------------------+---------------------+

共返回 1 行记录,花费 8934.00 ms.

GIN索引用=号性能就很差了。

- 其他 https://yq.aliyun.com/articles/272112?utm_content=m_35570

你可能感兴趣的:(DB)