热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

postgresl系列之NoSQL特性

本文是《PostgreSQL实战》的读书笔记,感兴趣的可以参看本书对应章节。一、PostgreSQL的NoSQL特性PostgreSQL不只是一个关系型数据库&#

本文是《PostgreSQL实战》的读书笔记,感兴趣的可以参看本书对应章节。


一、PostgreSQL的NoSQL特性

PostgreSQL不只是一个关系型数据库,同时支持非关系特性,而且逐步增加对非关系特性的支持。


1.1 为jsonb类型创建索引

jsonb数据类型支持GIN索引。

{"id":1,"user_id":122,"user_name":"1_joker","create_time":"2018-11-25 20:48:10"
}

tbl_user_jsonb中的user_info字段类型是jsonb 。在user_info创建GIN索引。

create index idx_gin ON tbl_user_jsonb USING gin(user_info);

jsonb上的GIN支持 @>??&?| 操作符。例如

-- 使用索引查询
select * from tbl_user_jsonb where user_info @> '{"user_name":"1_joker"}'-- 但是以下基于jsonb键值的查询不会走索引idx_gin:
select * from tbl_user_jsonb where user_info ->>'user_name' = '1_joker';-- 如果要提升基于json类型的键值检索效率,可以在jsonb类型对应的键值上创建索引:
create index idx_gin_user_infob_user_name ON tbl_user_jsonb Using btree(user_info->>'user_name')



1.2 json、jsonb读写性能测试

json写入时比jsonb快,但检索时比jsonb慢。原因:json存储格式为文本而jsonb为二进制,存储格式的不同使的两种json数据类型的处理效率不一样。json类型存储的内容和输入数据一样,当检索json数据时必须重新解析;而jsonb以二进制存储已解析好的数据,当检索jsonb数据时不需要重新解析

通过简答的例子测试json、jsonb的读写性能差异。

--1.创建user_ini表并插入200w数据。
create table user_ini(id int4,user_id int8,user_name character varying(64),create_time timestamp(6) with time zone default clock_timestamp()
);
--1.1插入数据
INSERT INTO user_ini(id,user_id,user_name)
SELECT r,round(random()*2000000),r||'_frances'
FROM generate_series(1,2000000) AS r;--2.使用user_ini表生成json、jsonb数据,创建user_ini_json,user_ini_jsonb表。
CREATE TABLE tbl_user_json(id serial,user_info json);CREATE TABLE tbl_user_jsonb(id serial,user_info jsonb);

json、 jsonb 表写性能测试

根据user_ini数据通过 row_to_json函数向表user_ini_json插入200万json数据。

INSERT INTO tbl_user_json(user_info) SELECT row_to_json(user_ini) FROM user_ini;

在这里插入图片描述

INSERT INTO tbl_user_jsonb(user_info) SELECT row_to_json(user_ini) FROM user_ini;

在这里插入图片描述
可以明显看出来,json的写性能要比jsonb好 。从占用空间来看,同样数量jsonb数据类型占用空间比json稍大。




json、jsonb表读性能测试

根据user_info字段的user_name键的值查询


注意:关闭并行查询 SET max_parallel_workers_per_gather = 0


EXPLAIN ANALYSE SELECT * FROM tbl_user_jsonb WHERE user_info ->>'user_name' = '1_frances';-- 执行计划
Seq Scan on tbl_user_jsonb (cost=0.00..73500.32 rows=10000 width=144) (actual time=0.800..591.076 rows=1 loops=1)Filter: ((user_info ->> 'user_name'::text) = '1_frances'::text)Rows Removed by Filter: 1999999
Planning time: 0.056 ms
Execution time: 591.101 ms

基于user_info字段的user_name 键值创建btree索引

CREATE INDEX idx_jsonb ON tbl_user_jsonb USING btree((user_info->>'user_name'));

再次执行上述查询:

EXPLAIN ANALYSE SELECT * FROM tbl_user_jsonb WHERE user_info ->>'user_name' = '1_frances';-- 执行计划
Bitmap Heap Scan on tbl_user_jsonb (cost=233.93..24043.95 rows=10000 width=144) (actual time=0.372..0.373 rows=1 loops=1)Recheck Cond: ((user_info ->> 'user_name'::text) = '1_frances'::text)Heap Blocks: exact=1-> Bitmap Index Scan on idx_jsonb (cost=0.00..231.43 rows=10000 width=0) (actual time=0.328..0.328 rows=1 loops=1)Index Cond: ((user_info ->> 'user_name'::text) = '1_frances'::text)
Planning time: 0.629 ms
Execution time: 0.429 ms

通过比较执行计划可以看出走了索引,并且SQL时间下降。



为了更好地对比 tbl_user_json、tbl_user_jsonb 表基于键值查询的效率,对user_info字段id键进行范围扫描以对比性能。

CREATE INDEX idx_gin_user_info_id ON tbl_user_json USING btree(((user_info ->>'id')::integer));CREATE INDEX idx_gin_user_infob_id ON tbl_user_jsonb USING btree(((user_info ->>'id')::integer));

--索引创建后,查询tbl_user_json表
EXPLAIN ANALYSE SELECT id,user_info->'id',user_info->'user_name' FROM tbl_user_json
WHERE(user_info->>&#39;id&#39;)::int4 > 1 AND (user_info->>&#39;id&#39;)::int4 < 10000;-- 执行计划
Bitmap Heap Scan on tbl_user_json (cost&#61;214.93..22741.47 rows&#61;10000 width&#61;68) (actual time&#61;1.830..41.511 rows&#61;9998 loops&#61;1)Recheck Cond: ((((user_info ->> &#39;id&#39;::text))::integer > 1) AND (((user_info ->> &#39;id&#39;::text))::integer < 10000))Heap Blocks: exact&#61;173-> Bitmap Index Scan on idx_gin_user_info_id (cost&#61;0.00..212.43 rows&#61;10000 width&#61;0) (actual time&#61;1.762..1.762 rows&#61;9998 loops&#61;1)Index Cond: ((((user_info ->> &#39;id&#39;::text))::integer > 1) AND (((user_info ->> &#39;id&#39;::text))::integer < 10000))
Planning time: 0.389 ms
Execution time: 42.467 ms

查询表tbl_user_json的user_info字段id键值在1到10000范围内走了索引。

EXPLAIN ANALYSE SELECT id,user_info->&#39;id&#39;,user_info->&#39;user_name&#39; FROM tbl_user_jsonb
WHERE(user_info->>&#39;id&#39;)::int4 > 1 AND (user_info->>&#39;id&#39;)::int4 < 10000;-- 执行计划
Bitmap Heap Scan on tbl_user_jsonb (cost&#61;214.93..24224.95 rows&#61;10000 width&#61;68) (actual time&#61;1.269..12.417 rows&#61;9998 loops&#61;1)Recheck Cond: ((((user_info ->> &#39;id&#39;::text))::integer > 1) AND (((user_info ->> &#39;id&#39;::text))::integer < 10000))Heap Blocks: exact&#61;213-> Bitmap Index Scan on idx_gin_user_infob_id (cost&#61;0.00..212.43 rows&#61;10000 width&#61;0) (actual time&#61;1.175..1.175 rows&#61;9998 loops&#61;1)Index Cond: ((((user_info ->> &#39;id&#39;::text))::integer > 1) AND (((user_info ->> &#39;id&#39;::text))::integer < 10000))
Planning time: 0.271 ms
Execution time: 13.074 ms

执行时间明显变短了。

从上面的测试看出&#xff0c;json写入比jsonb快&#xff0c;但检索时比jsonb慢。




二、全文索引对json和jsonb数据类型的支持

对于多数应用来说全文检索很少在数据库中实现&#xff0c;一般使用单独的全文检索引擎&#xff0c;例如基于SQL的全文检索引擎Sphinx。PostgreSQL支持全文检索&#xff0c;对于规模不大的应用如果不想搭建专门的搜索引擎&#xff0c;PostgreSQL的全文检索也可满足需求。



大部分检索需要通过数据库like操作匹配&#xff0c;这种检索方式的主要缺点&#xff1a;


  • 不能很好地支持索引&#xff0c;通常需要全表扫描检索数据&#xff0c;数据量大时检索性能很低。
  • 不能提供检索结果排序&#xff0c;当输出结果数据量非常大时表现更加明显

PostgreSQL全文检索有效地解决这个问题。PostgreSQL全文检索通过以下两种数据类型来实现。




tsvector

tsvector 全文检索数据类型代表一个被优化的可以基于搜索的文档&#xff0c;要将一串字符串转换成tsvector全文检索数据类型。

-- tsvectorSELECT &#39;Hello,cat,how are u? cat is smiling!&#39;::tsvector;-- &#39;Hello,cat,how&#39; &#39;are&#39; &#39;cat&#39; &#39;is&#39; &#39;smiling!&#39; &#39;u?&#39;
--可以看到&#xff0c;字符串的内容被分隔成好几段&#xff0c;但通过::tsvector只是做类型转换&#xff0c;没有进行数据标准处理
--对于英文全文检索可以通过函数 to_tsvecotr进行标准化&#xff1a;SELECT to_tsvector(&#39;english&#39; ,&#39;Hello cat,&#39;)
-- &#39;cat&#39;:2 &#39;hello&#39;:1

tsquery

tsquery 表示一个文本查询&#xff0c;存储用于搜索的词&#xff0c;并且支持布尔操作 &|!

--将字符串转换成 tsquery
SELECT &#39;hello&cat&#39;::tsquery;
-- &#39;hello&#39; & &#39;cat&#39;--上述只是转换成tsquery类型&#xff0c;而并没有做标准化&#xff0c;使用to_tsquery函数可以执行标准化SELECT to_tsquery(&#39;hello&cat&#39;);
-- &#39;hello&#39; & &#39;cat&#39;

--用于检索字符串是否包括"hello" 和 "cat"字符。
SELECT to_tsvector(&#39;english&#39;,&#39;Hello cat, how are u&#39;) &#64;&#64; to_tsquery(&#39;hello&cat&#39;);
-- 结果&#xff1a;t--2. 检索字符串是否包含字符"hello" 和 "dog"
SELECT to_tsvector(&#39;english&#39;,&#39;Hello cat, how are u&#39;) &#64;&#64; to_tsquery(&#39;hello&dog&#39;);
--结果&#xff1a;f



英文全文检索例子

在PostgreSQL10之前全文检索不支持json和jsonb数据类型。10版本则开始支持这两种类型。


推荐阅读
  • MySQL Decimal 类型的最大值解析及其在数据处理中的应用艺术
    在关系型数据库中,表的设计与SQL语句的编写对性能的影响至关重要,甚至可占到90%以上。本文将重点探讨MySQL中Decimal类型的最大值及其在数据处理中的应用技巧,通过实例分析和优化建议,帮助读者深入理解并掌握这一重要知识点。 ... [详细]
  • php更新数据库字段的函数是,php更新数据库字段的函数是 ... [详细]
  • 一个建表一个执行crud操作建表代码importandroid.content.Context;importandroid.database.sqlite.SQLiteDat ... [详细]
  • 您的数据库配置是否安全?DBSAT工具助您一臂之力!
    本文探讨了Oracle提供的免费工具DBSAT,该工具能够有效协助用户检测和优化数据库配置的安全性。通过全面的分析和报告,DBSAT帮助用户识别潜在的安全漏洞,并提供针对性的改进建议,确保数据库系统的稳定性和安全性。 ... [详细]
  • NX二次开发:UFUN点收集器UF_UI_select_point_collection详解
    本文介绍了如何在NX中使用UFUN库进行点收集器的二次开发,包括必要的头文件包含、初始化和选择点集合的具体实现。 ... [详细]
  • 2022年2月 微信小程序 app.json 配置详解:启用调试模式
    本文将详细介绍如何在微信小程序的 app.json 文件中启用调试模式(debug),并通过实际案例展示其配置方法和应用场景。 ... [详细]
  • IOS Run loop详解
    为什么80%的码农都做不了架构师?转自http:blog.csdn.netztp800201articledetails9240913感谢作者分享Objecti ... [详细]
  • 网站访问全流程解析
    本文详细介绍了从用户在浏览器中输入一个域名(如www.yy.com)到页面完全展示的整个过程,包括DNS解析、TCP连接、请求响应等多个步骤。 ... [详细]
  • Ext JS MVC系列一:环境搭建与框架概览
    本文主要介绍了如何在项目中使用Ext JS 4作为前端框架,并详细讲解了Ext JS 4的MVC开发模式。文章将从项目目录结构、相关CSS和JS文件的引用以及MVC框架的整体认识三个方面进行总结。 ... [详细]
  • 如何在Java中使用DButils类
    这期内容当中小编将会给大家带来有关如何在Java中使用DButils类,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。D ... [详细]
  • 在 Ubuntu 中遇到 Samba 服务器故障时,尝试卸载并重新安装 Samba 发现配置文件未重新生成。本文介绍了解决该问题的方法。 ... [详细]
  • 本文详细介绍了MySQL数据库的基础语法与核心操作,涵盖从基础概念到具体应用的多个方面。首先,文章从基础知识入手,逐步深入到创建和修改数据表的操作。接着,详细讲解了如何进行数据的插入、更新与删除。在查询部分,不仅介绍了DISTINCT和LIMIT的使用方法,还探讨了排序、过滤和通配符的应用。此外,文章还涵盖了计算字段以及多种函数的使用,包括文本处理、日期和时间处理及数值处理等。通过这些内容,读者可以全面掌握MySQL数据库的核心操作技巧。 ... [详细]
  • 通过使用Sqoop导入工具,可以精确控制并高效地将表数据的特定子集导入到HDFS中。具体而言,可以通过在导入命令中添加WHERE子句来指定所需的数据范围,从而在数据库服务器上执行相应的SQL查询,并将查询结果高效地存储到HDFS中。这种方法不仅提高了数据导入的灵活性,还确保了数据的准确性和完整性。 ... [详细]
  • 本文介绍了如何使用 Node.js 和 Express(4.x 及以上版本)构建高效的文件上传功能。通过引入 `multer` 中间件,可以轻松实现文件上传。首先,需要通过 `npm install multer` 安装该中间件。接着,在 Express 应用中配置 `multer`,以处理多部分表单数据。本文详细讲解了 `multer` 的基本用法和高级配置,帮助开发者快速搭建稳定可靠的文件上传服务。 ... [详细]
  • Python 伦理黑客技术:深入探讨后门攻击(第三部分)
    在《Python 伦理黑客技术:深入探讨后门攻击(第三部分)》中,作者详细分析了后门攻击中的Socket问题。由于TCP协议基于流,难以确定消息批次的结束点,这给后门攻击的实现带来了挑战。为了解决这一问题,文章提出了一系列有效的技术方案,包括使用特定的分隔符和长度前缀,以确保数据包的准确传输和解析。这些方法不仅提高了攻击的隐蔽性和可靠性,还为安全研究人员提供了宝贵的参考。 ... [详细]
author-avatar
PFwX代佳佳ZYYTHFQN
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有