PostgreSQL介绍
什么是PostgreSQL
PostgreSQL是一个功能强大的开源对象关系数据库管理系统(ORDBMS)。 用于安全地存储数据; 支持最佳做法,并允许在处理请求时检索它们。
PostgreSQL是跨平台的,可以在许多操作系统上运行,如Linux,FreeBSD,OS X,Solaris和Microsoft Windows等。
常用于联机事务处理OLTP(on-line transaction processing)、联机分析处理OLAP(On-Line Analytical Processing)。
PostgreSQL特点
- 稳定
得益于PostgreSQL的多进程架构,一个连接的异常并不影响主进程和其他连接,从而带来不错的稳定性
- 高性能
TPCC的性能测试显示PostgreSQL的性能与商业数据库基本在同一个层面上
- 丰富
查询丰富:且不说HASH\Merge\NestLoop JOIN,还有递归、树形(connect by)、窗口、rollup\cube\grouping sets、物化视图、SQL标准等,还有各种全文检索、正则表达式、模糊查询、相似度等。在这些之外,最重要的是PostgreSQL强大的基于成本的优化器,结合并行执行(并行扫瞄、并行JOIN等)和多种成本因子,带来各种各样丰富灵活高效的查询支持。
类型丰富:如高精度numeric, 浮点, 自增序列,货币,字节流,时间,日期,时间戳,布尔, 枚举,平面几何,立体几何,多维几何,地球,PostGIS,网络,比特流,全 文检索,UUID,XML,JSON,数组,复合类型,域类型,范围,树类型,化 学类型,基因序列,FDW, 大对象, 图像等。
[PS: 这里的数组,可以让用户像操作JAVA中的数组一样操作数据库中的数据,如 item[0][1]即表示二维数组中的一个元素,而item可以作为表的一个字段。]
或者,如果以上不够满足,你可以自定义自己的类型(create type),并且可以针对这些类型进行运算符重载,比如实现IP类型的加减乘除(其操作定义依赖于具体实现,意思是:你想让IP的加法是什么样子就是什么样子)。
另外还有各种索引的类型,如btree, hash, gist, sp-gist, gin, brin , bloom , rum 索引等。你甚至可以为自己定义的类型定制特定的索引和索引扫瞄。
功能丰富:PostgreSQL有一个无与伦比的特性——插件。其利用内核代码中的Hook,可以让你在不修改数据库内核代码的情况下,自主添加任意功能,如PostGIS、JSON、基因等,都是在插件中做了很多的自定义而又不影响任何内核代码从而满足丰富多样的需求。而PostgreSQL的插件,不计其数。
FDW机制更让你可以在同一个PostgreSQL中像操作本地表一样访问其他数据源,如Hadoop、MySQL、Oracle、Mongo等,且不会占用PG的过多资源。比如阿里开发的OSS_FDW就用于实现对OSS的读写。
PostgreSQL语法
PostgreSQL支持大部分SQL:2011特性[1]。
在psql
中可以使用\help
命令查看所有PostgreSQL语句的语法。使用\help &
可查看特定语句语法。
postgres=# \help WITH
Command: WITH
Description: retrieve rows from a table or view
Syntax:
[ WITH [ RECURSIVE ] with_query [, ...] ]
SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ]
[ * | expression [ [ AS ] output_name ] [, ...] ]
[ FROM from_item [, ...] ]
[ WHERE condition ]
[ GROUP BY grouping_element [, ...] ]
[ HAVING condition [, ...] ]
[ WINDOW window_name AS ( window_definition ) [, ...] ]
[ { UNION | INTERSECT | EXCEPT } [ ALL | DISTINCT ] select ]
[ ORDER BY expression [ ASC | DESC | USING operator ] [ NULLS { FIRST | LAST } ] [, ...] ]
[ LIMIT { count | ALL } ]
[ OFFSET start [ ROW | ROWS ] ]
[ FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } ONLY ]
[ FOR { UPDATE | NO KEY UPDATE | SHARE | KEY SHARE } [ OF table_name [, ...] ] [ NOWAIT | SKIP L
OCKED ] [...] ]
- INSERT
- SELECT
- UPDATE
- DELETE
- ORDER BY子句
- GROUP BY子句
- HAVING子句
- WHERE条件查询
- 表连接
- 等
PostgreSQL常用函数及操作符
字符串函数及操作符
- ||
语句 | 结果 |
---|---|
'Value: ' || 42 | Value: 42 |
'String' || null | null |
- concat(), concat_ws()
语句 | 结果 |
---|---|
concat('abc', null, 22) | abc22 |
concat_ws(',', 'abc', null, 33) | abc,33 |
- position()
语句 | 结果 |
---|---|
position('om' in 'Thomas') | 3 |
- substring()
语句 | 结果 |
---|---|
substring('Thomas' from 2 for 3) | hom |
substring('Thomas' from '^..') | Th |
https://www.postgresql.org/docs/10/static/functions-string.html
模式匹配
- LIKE
全量匹配(除非有%符号)
语句 | 结果 |
---|---|
'abc' LIKE '_b%' | t |
'abc' NOT LIKE '%c' | f |
- SIMILAR TO正则表达式
借用LIKE和部分POSIX正则表达式,全量匹配(除非有%符号)
可用的POSIX正则表达式:| * + ? {m} {m,} {m,n}
语句 | 结果 |
---|---|
'abc' SIMILAR TO 'a' | f |
'abc' SIMILAR TO '%(b|d)%' | t |
'abc' SIMILAR TO '(b|c)%' | f |
- POSIX正则表达式
语句 | 结果 |
---|---|
'thomas' ~ '.*thomas.*' | t |
'thomas' ~* '.*Thomas.*' | t |
'thomas' !~ '.*Thomas.*' | t |
'thomas' !~* '.*vadim.*' | t |
https://www.postgresql.org/docs/10/static/functions-matching.html
数据类型格式化函数
- to_char()
语句 | 结果 |
---|---|
to_char(current_timestamp, 'HH24:MI:SS') | 07:34:48 |
to_char(-0.1, '99.99') | ' -.10' |
to_char(1::numeric/2::numeric, 'FM990.00'); | '0.50' |
- to_date()
语句 | 结果 |
---|---|
to_date('05 Dec 2000', 'DD Mon YYYY') | 2000-12-05 |
- to_number()
语句 | 结果 |
---|---|
to_number('12,454.8-', '99G999D9S') | -12454.8 |
- to_timestamp()
语句 | 结果 |
---|---|
to_timestamp('05 Dec 2000', 'DD Mon YYYY') | 2000-12-05 00:00:00+00 |
日期、时间操作符及函数
- + - * /
语句 | 结果 |
---|---|
date '2001-09-28' + integer '7' | date '2001-10-05' |
date '2001-09-28' + time '03:00' | timestamp '2001-09-28 03:00:00' |
date '2001-09-28' - interval '1 hour' | timestamp '2001-09-27 23:00:00' |
900 * interval '1 second' | interval '00:15:00' |
interval '1 hour' / double precision '1.5' | interval '00:40:00' |
current_date, current_time, current_timestamp
date_part()
语句 | 结果 |
---|---|
date_part('hour', timestamp '2001-02-16 20:38:40') | 20 |
date_part('month', interval '2 years 3 months') | 3 |
- make_date(), make_time(), make_timestamp()
语句 | 结果 |
---|---|
make_date(2013, 7, 15) | date '2013-07-15' |
make_time(8, 15, 23.5) | time '08:15:23.5' |
make_timestamp(2013, 7, 15, 8, 15, 23.5) | timestamp '2013-07-15 08:15:23.5' |
条件表达式
- CASE
CASE WHEN condition THEN result
[WHEN ...]
[ELSE result]
END
CASE expression
WHEN value THEN result
[WHEN ...]
[ELSE result]
END
- COALESCE
COALESCE(value [, ...])
- NULLIF
NULLIF(value1, value2)
语句 | 结果 |
---|---|
SELECT CASE WHEN 3>2 THEN 'A' ELSE 'B' END | 'A' |
SELECT COALESCE(NULL,'A','B') | 'A' |
SELECT NULLIF('A','A') | NULL |
SELECT NULLIF('A','B') | 'A' |
聚集函数
- avg,count,max,min,sum
集合生成函数
- generate_series()
SELECT * FROM generate_series(2,4);
generate_series
-----------------
2
3
4
(3 rows)
SELECT generate_series(1.1, 4, 1.3);
generate_series
-----------------
1.1
2.4
3.7
(3 rows)
SELECT * FROM generate_series('2008-03-01 00:00'::timestamp, '2008-03-02 12:00', '10 hours');
generate_series
---------------------
2008-03-01 00:00:00
2008-03-01 10:00:00
2008-03-01 20:00:00
2008-03-02 06:00:00
(4 rows)
with子句(通用数据表表达式)
辅助报表与查询
WITH regional_sales AS (
SELECT region, SUM(amount) AS total_sales
FROM orders
GROUP BY region
), top_regions AS (
SELECT region
FROM regional_sales
WHERE total_sales > (SELECT SUM(total_sales)/10 FROM regional_sales)
)
SELECT region,
product,
SUM(quantity) AS product_units,
SUM(amount) AS product_sales
FROM orders
WHERE region IN (SELECT region FROM top_regions)
GROUP BY region, product;
数据修改语句
WITH moved_rows AS (
DELETE FROM products
WHERE
"date" >= '2010-10-01' AND
"date" < '2010-11-01'
RETURNING *
)
INSERT INTO products_log
SELECT * FROM moved_rows;
自定义函数及plpgsql
语法
CREATE [OR REPLACE] FUNCTION function_name(参数逗号隔开)
RETURNS 返回值类型 AS $body$
DECLARE //声明变量
变量名 变量类型 :=变量值;
例如:name char(20):='su';
BEGIN
/*函数体;包括DML语句;
特别注意:如果有返回值,要省略最后的return语句的话,则在函数体的最后必须是一个select语句且返回类型必须和上面声明的类型一样;
*/
RETURN 变量名//和上面返回的变量一样;
END
$body$
LANGUAGE plpgsql;
示例
create or replace function f_test() returns void as $$
declare
begin
for i in 1..1000 loop
execute 'insert into test select generate_series('||(i-1)*40000+1||','||i*40000||'),(random()::float)*'||i*0.0001||',clock_timestamp()';
end loop;
end;
$$ language plpgsql;
PostgreSQL实战
自增主键的实现
- 使用Sequence
CREATE SEQUENCE users_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
alter table users alter column id set default nextval('users_id_seq');
- 使用serial
CREATE TABLE users
(
id SERIAL primary key ,
name character varying,
password character varying
)
PostgreSQL会自动创建名为users_id_seq的序列,且MAXVALUE=2^63-1
多字段去重统计的实现
MySQL中可以使用COUNT(DISTINCT expr,[expr...])
统计多字段不同值的非空行数
PostgreSQL可以使用如下方式实现:
SELECT count(DISTINCT column1||'@'||column2) from table;
进阶
- 索引[2]
多列索引、复合索引、gin、bloom、前后模糊查询、正则查询
- 相似度分析[3]
相近、相仿、距离接近、性格接近等等类似这样的需求,对数据进行筛选
- 全文检索[4]
参考资料
官方文档:https://www.postgresql.org/docs/10/static/index.html
https://www.yiibai.com/postgresql
[1]https://www.postgresql.org/docs/10/static/features.html
[2]https://github.com/digoal/blog/blob/master/201612/20161231_01.md
https://github.com/digoal/blog/blob/master/201702/20170205_01.md[3]https://yq.aliyun.com/articles/59212
[4]https://www.postgresql.org/docs/10/static/functions-textsearch.html
http://blog.chinaunix.net/uid-20726500-id-4820580.html