postgrepsql学习
Posted weixin_42412601
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了postgrepsql学习相关的知识,希望对你有一定的参考价值。
目录
1、postgresql----索引失效
https://www.cnblogs.com/alianbog/p/5648455.html
2、postgrep查看sql是否使用索引
EXPLAIN ANALYZE select * FROM sys_order WHERE is_deleted = 1;
3、模糊查询like优化
一、 模糊查询没有使用索引:
PG中使用索引进行模糊查询
现在数据库中存在一个tb_user(id, name,age)表,并且已经针对name字段创建了索引tb_user_name_idx。
explain analyze select * from tb_user where name like '%aaa%';
发现该SQL语句在name字段上使用的是Seq Scan而不是Index Scan或Bitmap Heap Scan,执行时间在1s以上。
二、模糊查询使用索引:
使用pg_trgm插件
想要在模糊查询时在name字段上使用索引,需要执行如下SQL语句
CREATE EXTENSION pg_trgm;
CREATE INDEX tb_user_name_trgm_gist_idx ON tb_user USING GiST(name GiST_trgm_ops);
此时,再执行:
explain analyze select * from tb_user where name like '%aaa%';
发现该SQL语句在name字段上使用了Bitmap Heap Scan,使用到了新创建的索引,而且执行时间减少到20-30ms。
实际测试:
-- 使用索引: 4ms 5ms
-- 不使用索引:200ms 192ms 218ms
explain analyze select * from sys_order so where order_no like '%9ig_213858%';
4、postgrep自增主键
- 主键自增长的方式有三种:
sequence,serial,identity
https://www.cnblogs.com/wy123/p/13367486.html
postgrep
,使用identity
自增时,主键设置为GENERATED BY DEFAULT AS IDENTITY
,插入数据时,如果主键id=null
,它会优先使用用户传的id
作为主键,这就会报错了,可以再insert
的时候,加上OVERRIDING USER VALUE
,覆盖用户输入的值(使用系统列定义的自增值)identity
详解
https://www.izhangchao.com/internet/internet_228042.html
- 实际上
identify
列,也使用了序列,如下:生成的序列默认名为表名_id_seq
- 获取
identify
列自增长的下一个值,通过函数nextval
select nextval('test_onduplicatekey_id_seq');
在DBeaver
中直接点序列,就能看到各个表主键identity
生成的默认序列了,注意,是主键使用了identity
的方式自增时,才会有。
5、on CONFLICT
语法
insert into sys_user (username,password,email,org_id,is_deleted ,create_time,update_time,create_user_id,create_by)
values('lzh123','12345','12345678@qq.com',3,0,'2021-02-19 16:32:08','2021-02-19 16:32:08',1,'admin')
ON conflict(username,is_deleted) do update set email='66666666@qq.com',password='6666';
https://blog.csdn.net/nmgcfyxl/article/details/105773010
https://vegetable-chicken.blog.csdn.net/article/details/103733927
6、Postgrep使用json字段,存储json数据
- postgrep支持同时存储结构化数据和非结构化数据。字段支持json、jsonb的数据类型,一般使用jsonb。
- 表字段中有json的字段,数据源的url,要加上?stringtype=unspecified
- 存储json数据时,入参可以使用Object/Map接受json数据,接受到后,再用fastjson转成json数据,与数据库映射的实体类,json字段就使用String去接受json数据就行,然后就当做正常数据插入到数据库中就行了
//使用fastjson将对象转成json数据
String detail=JSON.toJSONString(sysOrder.getDetail());
7、postgrep json字段查询
学习文档:https://www.postgresql.org/docs/current/functions-json.html
-- json数据,可以看成是表里的json字段
-- ::JSON 表示声明前面的字符串或字段为一个JSON字符串对象
-- ->方式获取到的元素依然是json对象
-- ->>方式获取到的元素不是json了,是一个json字符串
-- ->2表示从json数组中,取索引下标为2的元素
select '[{"a":"foo"},{"b":"bar"},{"c":"baz"}]'::json -> 2;
select '[{"a":"foo"},{"b":"bar"},{"c":"baz"}]'::json ->> 2;
-- ->'c'表示取出key是'c'的元素的值
select '[{"a":"foo"},{"b":"bar"},{"c":"baz"}]'::json -> 2->'c';
-- 会报错,因为->> 2获取到的是一个字符串了,已经不是json对象,不能在通过->'c'获取数据
select '[{"a":"foo"},{"b":"bar"},{"c":"baz"}]'::json ->> 2->'c';
-- #> '{a,b,1}'表示获取a下的b,b下的索引为1的元素。
-- #>方式获取到的数据,依然是json对象
-- #>>方式获取到的数据,是字符串
select '{"a": {"b": ["foo","bar"]}}'::json #> '{a,b,1}'
select '{"a": {"b": ["foo","bar"]}}'::json #>> '{a,b,1}'
-- 是否第一个json对象{"a":1, "b":2},包含第二个json对象,返回布尔值
select '{"a":1, "b":2}'::jsonb @> '{"b":2}'
-- 是否第一个json对象被包含在第二个json对象中
select '{"b":2}'::jsonb <@ '{"a":1, "b":2}'
-- json对象中是否包含键为'b'的元素
select '{"a":1, "b":2}'::jsonb ? 'b'
-- json数组中是否包含元素a
select '["a", "b", "c"]'::jsonb ? 'a'
-- 文本数组array['e', 'a']中是否有元素,存在于json对象或数组中
select '{"a":1, "b":2, "c":3}'::jsonb ?| array['e', 'a']
select '["a", "b", "c"]'::jsonb ?| array['e', 'd']
-- 文本数组array['a', 'd']中是否所有元素,存在于json对象或数组中
select '["a", "b", "c"]'::jsonb ?& array['a', 'd']
select '{"a":1, "b":2, "c":3}'::jsonb ?& array['a', 'b']
应用:
这种方式,在使用mybatis-plus的apply拼接sql的时候,会把?当成动态参数。
select * from sys_order where detail @? '$.hotelMessage.scheduledDate ? (@ > "2001-12-04 11:10:32" && @ < "2020-12-04 11:10:32" )'
select * from sys_order where detail @? '$.residentsMessage[*].residentName ? (@ starts with "入住")'
这种方式,在使用mybatis-plus的apply拼接sql的时候,会存在sql注入的风险
select * from sys_order where detail @@ '$.residentsMessage[*].residentName starts with "入住"'
select * from sys_order where detail @@ '$.hotelMessage.scheduledDate > "2001-12-04 11:10:32" && $.hotelMessage.scheduledDate < "2020-12-04 11:10:32" '
如何避免sql注入的风险?
.apply(ObjectUtil.isNotEmpty(sysOrderQO.getResidentName()), "detail @@ {0}", "$.residentsMessage[*].residentName starts with \\"" + sysOrderQO.getResidentName() + "\\"")
.apply(ObjectUtil.isNotNull(sysOrderQO.getScheduledDateStart()), "detail @@ {0}", "$.hotelMessage.scheduledDate >= \\"" + minimumOfLocalDate(sysOrderQO.getScheduledDateStart()) + "\\"")
.apply(ObjectUtil.isNotNull(sysOrderQO.getScheduledDateEnd()), "detail @@ {0}", "$.hotelMessage.scheduledDate < \\"" + maximumOfLocalDate(sysOrderQO.getScheduledDateEnd()) + "\\"");
注意:{0}默认给加单引号
以上是关于postgrepsql学习的主要内容,如果未能解决你的问题,请参考以下文章