如果需要把不同的表放在不同的存储介质或不同的文件系统下,可以使用表空间
`CREATE TABLESPACE tablespace_name LOCATION 'directory'
[WITH (tablespace_option = value)]`
在创建数据库、表时可以指定表空间,以便将对象存储在特定的表空间上
表空间参数 tablespace_option :如果在比 I/O子系统更快或更慢的磁盘上存储表空间,则配置项会变得很有意义
CREATE DATABASE name
[ENCODING[=]encoding]
[TABLESPACE[=]tablespace_name]
[CONNECTION LIMIT[=]connlimit]
ENCODING:编码
TABLESPACE:表空间
创建数据库:
CREATE [[GLOBAL|LOCAL]{TEMPORARY|TEMP}|UNLOGGED] TABLE
[IF NOT EXIST] table_name([
{ column_name data_type [COLLATE collation][column_constraint
[...]]
|table_constraint
|LIKE source_table [like_option...]}
])
[INHERITS(parent_table[,...])]
[PARTITION BY{RANGE|LIST}({column_name|(expression)}
[COLLATE collation][opclass][,...])]
[WITH(storage_parameter[=value][,...])|WITH OIDS|WITHOUT OIDS]
[ON COMMIT{PERSERVE ROWS|DELETE ROWS|DROP}]
[TABLESPACE tablespace_name]
字段约束:
deptid int not null REFERENCES department(deptid)
表约束:
删除数据库表:
删除表时如果该表被其他表引用(外键),直接删除会报错,需添加 CASCADE 连带删除子表的外键约束 : DROP TABLE employee CASCADE
整型:smallint、integer、bigint
任意精度:numeric、decimal
decimal(6,2):表示总共位数6位,小数部分位数2位。如果插入的数字小数位数超过2,则自动进行四舍五入
浮点:real 6位精度、 double precision 15位精度、float(n) 指定精度。浮点类型会造成精度丢失,需要准确计算应该使用numeric类型。浮点类型特殊值(Infinity、-Infinity、NaN)
序列:smallserial、serial、bigserial 可用作自增主键
货币:money 可以接受 ‘¥10000.00’货币格式,货币符号由数据库 lc_monetary 参数决定
字符串:char(n)、varchar(n)、text 。n表示最多存储n个字符,text无长度限制
二进制:bytea
日期时间:
系统内部所有与时区相关的日期时间存的都是UTC时间,可以使用timezone参数指定本地时间
布尔:true、false、unknown
位串:bit(n) 、 bit varying(n)。n表示存储位的长度
枚举:CREATE TYPE week AS ENUM (‘Mon’、‘Tue’、‘Wed’)
几何类型:point、line、lseg、box、path、polygon、cricle
JSON类型:
SELECT ‘{“bar”:bar, "balance:7.7"}’::jsonb;
范围类型:int4range、int8range、numrange、tsrange、tstzrange、daterange
INSERT INTO range1 VALUES('[2017-01-01 07:00:00,2017-01-01 08:00:00]')
数组类型:
pay_by_month float[] 或 pay_by_month float array[]
INSERT INTO payment VALUES ‘{10000.23, 12030.2, 10000}’
或INSERT INTO payment VALUES ARRAY[10000.23, 12030.2, 10000]
SELECT * FROM payment WHERE 10000 = ANY(pay_by_month);
SELECT a||b FROM test_char
;[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][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 LOCKED][...]]
// 根据 insuranceid和sex字段进行分组,返回每组sex最小的一行数据(包含 insuranceid, empid, insurant 字段)
SELECT DISTINCT ON (insuranceid, sex) insuranceid, empid, insurant FROM emp_order_insurance ORDER BY sex;
翻页不能解决因为结果集过大导致的性能问题,因为翻页也是先排序再分页的,被OFFSET子句忽略的行仍然需要在服务器内部计算;
解决方案:
- 根据业务实际需求,看能否替换为下一页,上一页的功能,特别在ios, android端,完全的分页是不常见的。 这里可以把limit, offset,替换为>辅助索引(即搜索条件)id的方式。该id再调用时,需要返回给前端。
- 利用索引覆盖
select column_name from table_name where id in (select id from table where second_index = xxx limit 10 offset 10000) 先在子查询中,查找数据对应的数据库唯一id值,因为主键在辅助索引上就有,所以不用回归到聚簇索引的磁盘去拉取。再通过这些已经被limit出来的10个主键id,去查询聚簇索引。这样只会十次随机io。 在业务确实需要用分页的情况下,使用该方案可以大幅度提高性能。通常能满足性能要求。
// 购买了保险号为1001的所有员工信息
SELECT empid,empname
FROM employee a
WHERE EXISTS(SELECT 1 FROM emp_order_insurance b WHERE a.empid = b.empid and b.insuranceid = 1001);
EXISTS里表用于和外表连接的字段一定要建立索引。因为EXISTS子查询需要的工作内存较少,优化器匹配到1条索引后即刻返回,所以会选择使用索引,性能非常好!
IN 和 EXISTS的比较:
使用in ,sql语句是先执行子查询,也就是先查询b表,在查a表,
而使用exists是先查主表a ,再查字表b;
对于主表数据较多时,我们使用in速度比exist更快,反之,从表b较大时,使用exist速度更快
WHERE empid > ANY(SELECT empid FROM emp_order_insurance);
模糊查询性能提升:
//分别按照deptid、sex和全部进行分组
SELECT deptid,sex,COUNT(*)
FROM employee
GROUP BY GROUPING SETS (deptid, sex, ());
ROLLUP 和 CUBE可以简化分组集的写法
UNION [ALL]、 INTERSECT[ALL]、EXCEPT[ALL] ,加ALL则不会过滤重复的行
窗口函数对表中一系列与当前行有某种关联的行执行跨行计算,这与聚集函数类似。但窗口函数不会使多行聚合成一个单独的输出行,这与聚集函数不同,在查询中输出的每一行仍然保持独立
function_name ([expression[,expression...]]) OVER (window_definition)
window_definition的格式:
PARTITION BY expression[,...]]
[ORDER BY expression[ASC|DESC]]
PARTITION BY子句将查询的行进行分组,窗口函数会对各个分组作独立的处理
// 查询各部门的员工在所属部门中的工资排名
SELECT empid,salary, deptid, row_number()over(partition by deptid order by salary desc)rnum
FROM employee
ORDEr BY deptid,rnum
empid|salary|deptid|rnum
10001|100000|100001|1
10002|80000 |100001|2
10003|60000 |100001|3
10004|100000|100002|1
10005|70000 |100002|2
常用的窗口函数:
insert into department(deptid, deptname)
values(1001,'xx')
on conflict(deptid)
do update set createtime = now()
[do nothing]
//把a的department更新为b的department
UPDATE department a SET deptname = b.deptnam FROM
upd_dept b WHERE a.deptid = b.deptid;
DELETE FROM department a USING test b WHERE a.deptid = b.deptid;