|
|
|
@ -0,0 +1,216 @@
|
|
|
|
|
|
|
|
|
|
## 一、常用命令及SQL
|
|
|
|
|
|
|
|
|
|
+ 系统性能指标
|
|
|
|
|
```sql
|
|
|
|
|
1.当前连接数
|
|
|
|
|
select count(*) from pg_stat_activity where query <>'IDLE';
|
|
|
|
|
2.查看所有表
|
|
|
|
|
select * from pg_tables where schemaname='public';
|
|
|
|
|
3.查看表字段
|
|
|
|
|
select * from information_schema.columns where table_schema='public' and table_name='device';
|
|
|
|
|
4.查看表大小
|
|
|
|
|
select pg_size_pretty(pg_relation_size('device'))
|
|
|
|
|
5.使用表扫描最多的表
|
|
|
|
|
select * from pg_stat_user_tables where n_live_tup > 100000 and seq_scan > 0 order by seq_tup_read desc limit 10;
|
|
|
|
|
```
|
|
|
|
|
## 二、函数
|
|
|
|
|
|
|
|
|
|
### 1.字符串
|
|
|
|
|
+ 字符串拼接
|
|
|
|
|
```sql
|
|
|
|
|
'Post' || 'greSQL' = PostgreSQL
|
|
|
|
|
SELECT CONCAT ('CONCAT',' ', 'function')
|
|
|
|
|
```
|
|
|
|
|
+ 转大、小写
|
|
|
|
|
```sql
|
|
|
|
|
select upper('tom')
|
|
|
|
|
select lower('ABC')
|
|
|
|
|
```
|
|
|
|
|
+ 子串在字符串中的位置,可以替代like
|
|
|
|
|
```sql
|
|
|
|
|
select position('om' in 'Thomas')
|
|
|
|
|
```
|
|
|
|
|
+ 字符串截取
|
|
|
|
|
```sql
|
|
|
|
|
# 从下标0开始截取4个字符
|
|
|
|
|
select substr('month',0,4)
|
|
|
|
|
```
|
|
|
|
|
### 2.日期时间
|
|
|
|
|
+ 获取当前时间绝对秒
|
|
|
|
|
```sql
|
|
|
|
|
select floor(extract(epoch from now()))
|
|
|
|
|
```
|
|
|
|
|
+ 日期转字符串
|
|
|
|
|
```sql
|
|
|
|
|
select to_char(now(),'yyyy-MM-dd HH24:mi:ss')
|
|
|
|
|
```
|
|
|
|
|
+ 字符串转日期
|
|
|
|
|
```sql
|
|
|
|
|
select to_date('1992-04-12','yyyy-MM-dd')
|
|
|
|
|
```
|
|
|
|
|
+ 当前时间、时间戳
|
|
|
|
|
```sql
|
|
|
|
|
select current_timestamp,now();
|
|
|
|
|
```
|
|
|
|
|
+ 字符串转时间戳
|
|
|
|
|
```sql
|
|
|
|
|
select to_timestamp('2024-03-21 14:03:14','yyyy-MM-dd HH24:mi:ss')
|
|
|
|
|
```
|
|
|
|
|
+ 获取当前日期
|
|
|
|
|
```sql
|
|
|
|
|
select current_date;
|
|
|
|
|
```
|
|
|
|
|
+ 获取6个月之前时间
|
|
|
|
|
```sql
|
|
|
|
|
select to_char((select now() - interval '6 month'),'yyyy-MM-dd hh24:mi:ss')
|
|
|
|
|
```
|
|
|
|
|
+ 计算时间差
|
|
|
|
|
```sql
|
|
|
|
|
1.天数(day可以换成month,year)
|
|
|
|
|
select date_part('day','2019-01-01'::date-'2011-10-02'::date)
|
|
|
|
|
|
|
|
|
|
2.秒
|
|
|
|
|
(extract('epoch' from a.pass_time::timestamp) - extract('epoch' from b.snap_time::timestamp))
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 3.窗口函数
|
|
|
|
|
|
|
|
|
|
窗口函数不是将一组数据汇总为单个结果;而是针对每一行数据,基于和它相关的一组数据计算出一个结果
|
|
|
|
|
![[Pasted image 20240501095744.png]]
|
|
|
|
|
|
|
|
|
|
窗口函数的定义如下:
|
|
|
|
|
```text
|
|
|
|
|
window_function ( expression, ... ) OVER (
|
|
|
|
|
PARTITION BY ...
|
|
|
|
|
ORDER BY ...
|
|
|
|
|
frame_clause
|
|
|
|
|
)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
| 函数类型 | 名称 | 用途 |
|
|
|
|
|
| ---- | ------------ | ---------------------------------------------------- |
|
|
|
|
|
| 聚合函数 | AVG | 平均值 |
|
|
|
|
|
| 聚合函数 | COUNT | 行数 |
|
|
|
|
|
| 聚合函数 | MAX | 最大值 |
|
|
|
|
|
| 聚合函数 | MIN | 最小值 |
|
|
|
|
|
| 聚合函数 | SUM | 总数 |
|
|
|
|
|
| 排名函数 | ROW_NUMBER | 为分区中的每行数据分配一个序列号,序列号从 1 开始分配 |
|
|
|
|
|
| 排名函数 | RANK | 计算每行数据在其分区中的名次;如果存在名次相同的数据,后续的排名将会产生跳跃 |
|
|
|
|
|
| 排名函数 | DENSE_RANK | 计算每行数据在其分区中的名次;即使存在名次相同的数据,后续的排名也是连续的值 |
|
|
|
|
|
| 排名函数 | PERCENT_RANK | 以百分比的形式显示每行数据在其分区中的名次;如果存在名次相同的数据,后续的排名将会产生跳跃 |
|
|
|
|
|
| 排名函数 | CUME_DIST | 计算每行数据在其分区内的累积分布,也就是该行数据及其之前的数据的比率;取值范围大于 0 并且小于等于 1 |
|
|
|
|
|
| 排名函数 | NTILE | 将分区内的数据分为 N 等份,为每行数据计算其所在的位置 |
|
|
|
|
|
| 取值函数 | FIRST_VALUE | 返回窗口内第一行的数据 |
|
|
|
|
|
| 取值函数 | LAST_VALUE | 返回窗口内最后一行的数据 |
|
|
|
|
|
| 取值函数 | NTH_VALUE | 返回窗口内第 N 行的数据 |
|
|
|
|
|
| 取值函数 | LAG | 返回分区中当前行之前的第 N 行的数据 |
|
|
|
|
|
| 取值函数 | LEAD | 返回分区中当前行之后第 N 行的数据 |
|
|
|
|
|
|
|
|
|
|
#### 3.1 排名窗口函数
|
|
|
|
|
以下示例按照部门为单位,计算员工的月薪排名:
|
|
|
|
|
|
|
|
|
|
```sql
|
|
|
|
|
SELECT d.department_name "部门名称", concat(e.first_name, ',' , e.last_name) "姓名", e.salary "月薪",
|
|
|
|
|
ROW_NUMBER() OVER (PARTITION BY e.department_id ORDER BY e.salary DESC) AS "row_number",
|
|
|
|
|
RANK() OVER (PARTITION BY e.department_id ORDER BY e.salary DESC) AS "rank",
|
|
|
|
|
DENSE_RANK() OVER (PARTITION BY e.department_id ORDER BY e.salary DESC) AS "dense_rank",
|
|
|
|
|
PERCENT_RANK() OVER (PARTITION BY e.department_id ORDER BY e.salary DESC) AS "percent_rank"
|
|
|
|
|
FROM employees e
|
|
|
|
|
JOIN departments d ON (e.department_id = d.department_id)
|
|
|
|
|
WHERE d.department_name in ('IT', 'Purchasing')
|
|
|
|
|
ORDER BY 1, 4;
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
![[Pasted image 20240501102554.png]]
|
|
|
|
|
ROW_NUMBER 函数为每个员工分配了一个连续的数字编号,可以看作是一种排名。IT 部门的“Valli,Pataballa”和“David,Austin”的月薪相同,但是编号不同;
|
|
|
|
|
|
|
|
|
|
RANK 函数为每个员工指定了一个名次,IT 部门的“Valli,Pataballa”和“David,Austin”的名次都是 3;而且在他们之后的“Diana,Lorentz”的名次为 5,产生了跳跃;
|
|
|
|
|
|
|
|
|
|
DENSE_RANK 函数为每个员工指定了一个名次,IT 部门的“Valli,Pataballa”和“David,Austin”的名次都是 3;在他们之后的“Diana,Lorentz”的名次为 4,名次是连续值;
|
|
|
|
|
|
|
|
|
|
PERCENT_RANK 函数按照百分比指定名次,取值位于 0 到 1 之间。其中“Diana,Lorentz”的百分比排名为 1,也产生了跳跃。
|
|
|
|
|
|
|
|
|
|
以上SQL的简化写法:
|
|
|
|
|
```sql
|
|
|
|
|
SELECT d.department_name "部门名称", concat(e.first_name, ',' , e.last_name) "姓名", e.salary "月薪",
|
|
|
|
|
ROW_NUMBER() OVER w AS "row_number",
|
|
|
|
|
RANK() OVER w AS "rank",
|
|
|
|
|
DENSE_RANK() w AS "dense_rank",
|
|
|
|
|
PERCENT_RANK() w AS "percent_rank"
|
|
|
|
|
FROM employees e
|
|
|
|
|
JOIN departments d ON (e.department_id = d.department_id)
|
|
|
|
|
WHERE d.department_name in ('IT', 'Purchasing')
|
|
|
|
|
WINDOW w AS (PARTITION BY e.department_id ORDER BY e.salary DESC)
|
|
|
|
|
ORDER BY 1, 4;
|
|
|
|
|
```
|
|
|
|
|
其中,`WINDOW`定义了一个窗口变量 w,然后在窗口函数的 OVER 子句中使用了该变量;这样可以简化函数的输入。
|
|
|
|
|
|
|
|
|
|
以下语句演示了 CUME_DIST 和 NTILE 函数的作用:
|
|
|
|
|
```sql
|
|
|
|
|
SELECT concat(first_name, ',' , last_name) "姓名", hire_date AS "入职日期",
|
|
|
|
|
CUME_DIST() OVER (ORDER BY hire_date) AS "累积占比",
|
|
|
|
|
NTILE(100) OVER (ORDER BY hire_date) AS "相对位置"
|
|
|
|
|
FROM employees;
|
|
|
|
|
```
|
|
|
|
|
![[Pasted image 20240501102825.png]]
|
|
|
|
|
其中,CUME_DIST 函数显示 2001-01-13 以及之前入职的员工大概有 0.9%(1/107);NTILE(100) 函数表明前 1% 入职的员工有“Lex,De Haan”和“Hermann,Baer”,由于员工总数为 107,所以不是完全准确。
|
|
|
|
|
#### 3.2 取值窗口函数
|
|
|
|
|
|
|
|
|
|
以下语句使用 FIRST_VALUE、LAST_VALUE 以及 NTH 函数分别获取每个部门内部月薪最高、月薪最低以及月薪第三高的员工:
|
|
|
|
|
```sql
|
|
|
|
|
SELECT department_id, first_name, last_name, salary,
|
|
|
|
|
FIRST_VALUE(salary) OVER w,
|
|
|
|
|
LAST_VALUE(salary) OVER w,
|
|
|
|
|
NTH_VALUE(salary, 3) OVER w
|
|
|
|
|
FROM employees
|
|
|
|
|
WINDOW w AS (PARTITION BY department_id ORDER BY salary desc ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
|
|
|
|
|
ORDER BY department_id, salary DESC;
|
|
|
|
|
```
|
|
|
|
|
![[Pasted image 20240501104752.png]]
|
|
|
|
|
LAG 和 LEAD 函数同样用于计算销量数据的环比/同比增长
|
|
|
|
|
```sql
|
|
|
|
|
WITH sales_monthly AS (
|
|
|
|
|
SELECT product, to_char(saledate,'YYYYMM') ym, sum(amount) sum_amount
|
|
|
|
|
FROM sales_data
|
|
|
|
|
GROUP BY product, to_char(saledate,'YYYYMM')
|
|
|
|
|
)
|
|
|
|
|
SELECT product AS "产品", ym "年月", sum_amount "销量",
|
|
|
|
|
(sum_amount - LAG(sum_amount, 1) OVER (PARTITION BY product ORDER BY ym))/
|
|
|
|
|
LAG(sum_amount, 1) OVER (PARTITION BY product ORDER BY ym) * 100 AS "环比增长率(%)"
|
|
|
|
|
FROM sales_monthly
|
|
|
|
|
ORDER BY product, ym;
|
|
|
|
|
```
|
|
|
|
|
![[Pasted image 20240501105012.png]]
|
|
|
|
|
首先,创建一个通用表表达式 sales_monthly,得到了不同产品每个月的销量汇总;LAG(sum_amount, 1) 表示获取上一期的销量;当前月份的销量减去上个月的销量,再除以上个月的销量,就是环比增长率。
|
|
|
|
|
|
|
|
|
|
### 4.正则表达式
|
|
|
|
|
|
|
|
|
|
```sql
|
|
|
|
|
-- 提取数字
|
|
|
|
|
NULLIF(regexp_replace(po_number, '\D','','g'), '')::numeric
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## 三、索引
|
|
|
|
|
[PostgreSQL 14种索引的原理和应用场景 - 简书 (jianshu.com)](https://www.jianshu.com/p/6aedd1b79dba)
|
|
|
|
|
|
|
|
|
|
| 索引 | 原理 | 场景 | 适用的数据类型 | 版本限制 |
|
|
|
|
|
| ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------- | ---- |
|
|
|
|
|
| btree | b-tree适合所有的数据类型,支持排序,支持大于、小于、等于、大于或等于、小于或等于的搜索 | | 所有 | 无 |
|
|
|
|
|
| hash | hash索引存储的是被索引字段VALUE的哈希值,只支持等值查询。 | | 所有 | 无 |
|
|
|
|
|
| gin | 当需要搜索多值类型内的VALUE时,适合多值类型,例如数组、全文检索、TOKEN。(根据不同的类型,支持相交、包含、大于、在左边、在右边等搜索) | | | |
|
|
|
|
|
| gist | GiST是一个通用的索引接口,可以使用GiST实现b-tree, r-tree等索引结构。不同的类型,支持的索引检索也各不一样。 | 例如: <br>1、几何类型,支持位置搜索(包含、相交、在上下左右等),按距离排序。 <br>2、范围类型,支持位置搜索(包含、相交、在左右等)。 <br>3、IP类型,支持位置搜索(包含、相交、在左右等)。 <br>4、空间类型(PostGIS),支持位置搜索(包含、相交、在上下左右等),按距离排序。 <br>5、标量类型,支持按距离排序 | | |
|
|
|
|
|
| sp-gist | SP-GiST类似GiST,是一个通用的索引接口,但是SP-GIST使用了空间分区的方法,使得SP-GiST可以更好的支持非平衡数据结构,例如quad-trees, k-d tree, radis tree。 | 应用场景 :<br>1、几何类型,支持位置搜索(包含、相交、在上下左右等),按距离排序。 <br>2、范围类型,支持位置搜索(包含、相交、在左右等)。 <br>3、IP类型,支持位置搜索(包含、相交、在左右等)。 | | |
|
|
|
|
|
| brin | BRIN 索引是块级索引,有别于B-TREE等索引,BRIN记录并不是以行号为单位记录索引明细,而是记录每个数据块或者每段连续的数据块的统计信息。因此BRIN索引空间占用特别的小,对数据写入、更新、删除的影响也很小。 | 时序数据,在时间或序列字段创建BRIN索引,进行等值、范围查询时效果很棒。 | | |
|
|
|
|
|
| rum | rum 是一个索引插件,由Postgrespro开源,适合全文检索,属于GIN的增强版本。 <br>增强包括: <br>1、在RUM索引中,存储了lexem的位置信息,所以在计算ranking时,不需要回表查询(而GIN需要回表查询)。 <br>2、RUM支持phrase搜索,而GIN无法支持。 <br>3、在一个RUM索引中,允许用户在posting tree中存储除ctid(行号)以外的字段VALUE,例如时间戳。 | RUM不仅支持GIN支持的全文检索,还支持计算文本的相似度值,按相似度排序等。同时支持位置匹配,例如(速度与激情,可以采用"速度" <2> "激情" 进行匹配,而GIN索引则无法做到) | | |
|
|
|
|
|
| bloom | bloom索引接口是PostgreSQL基于bloom filter构造的一个索引接口,属于lossy索引,可以收敛结果集(排除绝对不满足条件的结果,剩余的结果里再挑选满足条件的结果),因此需要二次check,bloom支持任意列组合的等值查询。 <br>bloom存储的是签名,签名越大,耗费的空间越多,但是排除更加精准。有利有弊 | | | |
|
|
|
|
|
| zombodb | zombodb是PostgreSQL与ElasticSearch结合的一个索引接口,可以直接读写ES | 与ES结合,实现SQL接口的搜索引擎,实现数据的透明搜索 | | |
|
|
|
|
|
| bitmap | bitmap索引是Greenplum的索引接口,类似GIN倒排,只是bitmap的KEY是列的值,VALUE是BIT(每个BIT对应一行),而不是行号list或tree | 当某个字段的唯一值个数在100到10万之间(超出这个范围,不建议使用bitmap)时,如果表的记录数特别多,而且变更不频繁(或者是AO表),那么很适合BITMAP索引,bitmap索引可以实现快速的多个或单个VALUE的搜索。因为只需要对行号的BITMAP进行BIT与或运算,得到最终的BITMAP,从最终的BITMAP映射到行进行提取。 <br>bitmap与btree一样,都支持 等于,大于,小于,大于等于,小于等于的查询。 | | |
|
|
|
|
|
| 表达式索引 | 表达式索引也是PostgreSQL特有的特性,例如用户的数据需要转换后查询,例如某些设备上传的地理坐标的坐标系不符合国标,需要转换为国内的空间坐标来查询。 <br>那么可以针对这类字段,创建表达式索引,将转换过程放到表达式中,查询时也使用表达式进行查询。 | CREATE INDEX ods_ht_transport_realtime_pass_time_idx ON ods_ht_transport_realtime ((pass_time::DATE)); 函数索引 | | |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 四、事务
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 五、常见问题
|