PostgreSQL中使用UUID

PostgreSQL中使用UUID,第1张

UUID(Universal Unique Identifier)或者 GUID(Globally Unique Identifier)是一个 128 比特的数字,可以用于唯一标识每个网络对象或资源。由于它的生成机制,一个 UUID 可以保证几乎不会与其他 UUID 重复,因此常常用于生成数据库中的主键值。

1.pgcrypto 模块提供的 uuid

PostgreSQL 提供了一个用于加/解密的扩展模块 pgcrypto,其中的 gen_random_uuid() 函数可以用于返回一个 version 4 的随机 UUID。

2.uuid-ossp 模块提供的 uuid

uuid-ossp模块提供函数使用几种标准算法之一产生通用唯一标识符(UUID)。还提供产生某些特殊 UUID 常量的函数。

1.将当前目录转移到 PostgreSQL 源代码目录下的 contrib;如:

2.执行如下命令来安装扩展模块

如果要安装 uuid-ossp 模块,需要在执行安装扩展模块之前,执行 configure 并添加 --with-uuid=xxx,xxx取值为:

然后再执行安装扩展模块的命令。

3.检查是否安装,在 PostgreSQL 的安装目录下的 /share/extension 目录下,查看是否有模块相关的文件。如:

注: gen_random_uuid() 从 PostgreSQL 13 开始成为了一个内置函数

如果您所使用的PostgreSQL版本在13以上,则不需要执行如下语句:

生成uuid:

如果想要生成没有中划线(-)的 UUID 字符串,可以使用 REPLACE 函数:

查看包含的函数:

执行如下命令生成 uuid:

分区介绍:

一、什么是分区?

所谓分区,就是将一个表分成多个区块进行 *** 作和保存,从而降低每次 *** 作的数据,提高性能。而对于应用来说则是透明的,从逻辑上看只有一张表,但在物理上这个表可能是由多个物理分区组成的,每个分区都是独立的对象,可以进行独立处理。

二、分区作用

1.可以逻辑数据分割,分割数据能够有多个不同的物理文件路径。

2.可以存储更多的数据,突破系统单个文件最大限制。

3.提升性能,提高每个分区的读写速度,提高分区范围查询的速度。

4.可以通过删除相关分区来快速删除数据

5.通过跨多个磁盘来分散数据查询,从而提高磁盘I/O的性能。

6.涉及到例如SUM()、COUNT()这样聚合函数的查询,可以很容易的进行并行处理。

7.可以备份和恢复独立的分区,这对大数据量很有好处。

三、分区能支持的引擎

MySQL支持大部分引擎创建分区,入MyISAM、InnoDB等;不支持MERGE和CSV等来创建分区。同一个分区表中的所有分区必须是同一个存储引擎。值得注意的是,在MySQL8版本中,MyISAM表引擎不支持分区。

四、确认MySQL支持分区

从MySQL5.1开始引入分区功能,可以如下方式查看是否支持:

老版本用:SHOW VARIABLES LIKE '%partition%'

新版本用:show plugins

五、分区类型

1. RANGE分区:基于属于一个给定连续区间的列值,把多行分配给分区。

例如,可以将一个表通过年份划分成两个分区,2001 -2010年、2011-2020。

2. LIST分区:类似于RANGE分区,LIST是列值匹配一个离散值集合中的某个值来进行选择。

比如 根据字段 把值为1、3、5的放到一起,2、4、6的另外放到一起 等等...

3. HASH分区:基于用户定义的表达式的返回值来进行选择分区,该表达式使用将要插入到表中的这些行的列值来进行计算,这个函数必须产生非负整数值。

通过HASH运算来进行分区,分布的比较均匀

4. KEY分区:类似于按HASH分区,由MySQL服务器提供其自身的哈希函数。

按照KEY进行分区类似于按照HASH分区

六、使用分区注意事项

1. 如果表中存在primary key 或者 unique key 时,分区的列必须是paimary key或者unique key的一个组成部分,也就是说,分区函数的列只能从pk或者uk这些key中取子集

2. 如果表中不存在任何的paimary key或者unique key,则可以指定任何一个列作为分区列

3. 5.5版本前的RANGE、LIST、HASH分区要求分区键必须是int;MySQL5.5及以上,支持非整形的RANGE和LIST分区,即:range columns 和 list columns (可以用字符串来进行分区)。

七、分区命名

1. 分区的名字基本上遵循其他MySQL 标识符应当遵循的原则,例如用于表和数据库名字的标识符。应当注意的是,分区的名字是不区分大小写的。

2. 无论使用何种类型的分区,分区总是在创建时就自动的顺序编号,且从0开始记录。

八、 创建分区

1. RANGE分区:

解读:以上为 uuid小于5时放到p0分区下,uuid大于5且小于10放到p1分区下,uuid大于10且小于15放到p2分区下,uuid大于15 一直到最大值的存在p3分区下

2. LIST分区:

解读:以上为uuid 等于1/2/3/5时放到p0分区,7/9/10放到p1分区,11/15放到p2分区。当时用insert into时 如果uuid的值不存在p0/p1/p2分区时,则会插入失败而报错。

3. HASH分区:

HASH分区主要用来确保数据在预先确定数目的分区中平均分布。在RANGE分区和LIST分区中必须明确指定一个指定的列值或列值集合以指定应该保存在哪个分区中。而在HASH分区中,MySQL会自动完成这些工作,要做的只是基于将要被哈希的列值指定一个表达式,以及指定被分区的表将要被分割成的分区数量,如:

解读:MySQL自动创建3个分区,在执行insert into时,根据插入的uuid通过算法来自动分配区间。

注意:

(1) 由于每次插入、更新、删除一行,这个表达式都要计算一次,这意味着非常复杂的表达式可能会引起性能问题,尤其是在执行同时影响大量行的运算(例如批量插入)的时候。

(2) 最有效率的哈希函数是只对单个表列进行计算,并且它的值随列值进行一致的增大或减小,因为这考虑了在分区范围上的“修剪”。也就是说,表达式值和它所基于的列的值变化越接近,就越能有效地使用该表达式来进行HASH分区。

3.1:线性HASH分区

线性HASH分区在“PARTITION BY”子句中添加“LINEAR”关键字。

线性HASH分区的有点在于增加、删除、合并和拆分分区将变得更加快捷,有利于处理含有及其大量数据的表。它的缺点在于各个分区间数据的分布不大可能均衡。

4. KEY分区

类似于HASH分区,HASH分区允许用户自定义的表达式,而KEY分区则不允许使用用户自定义的表达式;HASH分区只支持整数分区,KEY分区支持除了blob和text类型之外的其他数据类型分区。

与HASH分区不同,创建KEY分区表的时候,可以不指定分区键,默认会选择使用主键或唯一键作为分区键,没有主键或唯一键,就必须指定分区键。

解读:根据分区键来进行分区

5. 子分区

子分区是分区表中,每个分区的再次分割,适合保存非常大量的数据。

解读:主分区使用RANGE按照年来进行分区,有3个RANGE分区。这3个分区中又被进一步分成了2个子分区,实际上,整个表被分成了3 * 2 = 6个分区。每个子分区按照天进行HASH分区。小于2017的放在一起,2017-2020的放在一起,大于2020的放在一起。

注意:

(1) 在MySQL5.1中,对于已经通过RANGE或LIST分区了的表在进行子分区是可能的。子分区既可以使用HASH分区,也可以使用KEY分区。这也被称为复合分区。

(2) 每个分区必须有相同数量的子分区。

(3) 如果在一个分区表上的任何分区上使用SUBPARTITION来明确定义任何子分区,那么就必须定义所有的子分区。

(4) 每个SUBPARTITION子句必须包含(至少)子分区的一个名字。

(5) 在每个子分区内,子分区的名字必须是惟一的,目前在整个表中,也要保持唯一。例如:

子分区可以用于特别大的表,可以在多个磁盘间分配数据和索引。例如:

九、MySQL分区处理NULL值的方式

十、分区管理概述

可以对分区进行添加、删除、重新定义、合并或拆分等管理 *** 作。

① RANGE和LIST分区的管理

1. 删除分区语句如:alter table tbl_test drop partition p0

注意:

(1) 当删除了一个分区,也同时删除了该分区中所有的数据。

(2) 可以通过show create table tbl_test来查看新的创建表的语句。

(3) 如果是LIST分区的话,删除的数据不能新增进来,因为这些行的列值包含在已经删除了的分区的值列表中。

2. 添加分区语句如:alter table tbl_test add partition(partition p3 values less than(50))

注意:

(1) 对于RANGE分区的表,只可以添加新的分区到分区列表的最高端。

(2) 对于LIST分区的表,不能添加已经包含在现有分区值列表中的任意值。

3. 如果希望能不丢失数据的条件下重新定义分区,可以使用如下语句:

REORGANIZE会对分区的数据进行重构。

ALTER TABLE tbl_name REORGANIZE PARTITION partition_list INTO(partition_definitions)

(1) 拆分分区如:

ALTER TABLE tbl_name REORGANIZE PARTITION partition_list INTO(partition s0 values less than(5),partition s1 values less than(10))

或者如:

ALTER TABLE tbl_name REORGANIZE PARTITION p0 INTO(partition s0 values in(1,2,3), partition s1 values in(4,5))

(2) 合并分区如:ALTER TABLE tbl_name REORGANIZE PARTITION s0,s1 INTO(partition p0 values in(1,2,3,4,5))

4. 删除所有分区,但保留数据,形式:ALTER TABLE tbl_name remove partitioning

② HASH和KEY分区的管理

1. 减少分区数量语句如:ALTER TABLE tbl_name COALESCE PARTITION 2

2. 添加分区数量语句如:ALTER TABLE tbl_name add PARTITION partitions 2

③ 其他分区管理语句

1. 重建分区:类似于先删除保存在分区中的所有记录,然后重新插入它们,可用于整理分区碎片。如:ALTER table tbl_name REBUILD PARTITION p2,p3

2. 优化分区:如果从分区中删除了大量的行,或者对一个带有可变长度的行(也就是说,有VARCHAR,BLOB或TEXT类型的列)做了许多修改,可以使用 ALTER TABLE tbl_name OPTIMIZE PARTITION来收回没有使用的空间,并整理分区数据文件的碎片。如:ALTER TABLE tbl_name OPTIMIZE PARTITION p2,p3

3. 分析分区:读取并保存分区的键分布,如:ALTER TABLE tbl_name ANALYZE PARTITION p2,p3

4. 检查分区:检查分区中的数据或索引是否已经被破坏,如:ALTER TABLE tbl_name CHECK PARTITION p2,p3

5. 修补分区:修补被破坏的分区,如:ALTER TABLE tbl_name REPAIR PARTITION p2,p3

十、查看分区信息

1. 查看分区信息:select * from information_schema.partitions where table_schema='arch1' and table_name = 'tbl_test' G

2. 查看分区上的数据:select * from tbl_test partition(p0)

3. 查看MySQL会 *** 作的分区:explain partitions select * from tbl_test where uuid = 2

十一、 局限性

1. 最大分区数目不能超过1024,一般建议对单表的分区数不要超过50个。

2. 如果含有唯一索引或者主键,则分区列必须包含在所有的唯一索引或者主键在内。

3. 不支持外键。

4. 不支持全文索引,对分区表的分区键创建索引,那么这个索引也将被分区。

5. 按日期进行分区很合适,因为很多日期函数可以用。但是对字符串来说合适的分区函数不太多。

6. 只有RANGE和LIST分区能进行子分区,HASH和KEY分区不能进行子分区。

7. 临时表不能被分区。

8. 分区表对于单条记录的查询没有优势。

9. 要注意选择分区的成本,没插入一行数据都需要按照表达式筛选插入的分区。

10. 分区字段尽量不要可以为null

很多使用Elasticsearch的同学会关心数据存储在ES中的存储容量,会有这样的疑问:xxTB的数据入到ES会使用多少存储空间。这个问题其实很难直接回答的,只有数据写入ES后,才能观察到实际的存储空间。比如同样是1TB的数据,写入ES的存储空间可能差距会非常大,可能小到只有300~400GB,也可能多到6-7TB,为什么会造成这么大的差距呢?究其原因,我们来探究下Elasticsearch中的数据是如何存储。文章中我以Elasticsearch 2.3版本为示例,对应的lucene版本是5.5,Elasticsearch现在已经来到了6.5版本,数字类型、列存等存储结构有些变化,但基本的概念变化不多,文章中的内容依然适用。

Elasticsearch对外提供的是index的概念,可以类比为DB,用户查询是在index上完成的,每个index由若干个shard组成,以此来达到分布式可扩展的能力。比如下图是一个由10个shard组成的index。

shard是Elasticsearch数据存储的最小单位,index的存储容量为所有shard的存储容量之和。Elasticsearch集群的存储容量则为所有index存储容量之和。

一个shard就对应了一个lucene的library。对于一个shard,Elasticsearch增加了translog的功能,类似于HBase WAL,是数据写入过程中的中间数据,其余的数据都在lucene库中管理的。

所以Elasticsearch索引使用的存储内容主要取决于lucene中的数据存储。

下面我们主要看下lucene的文件内容,在了解lucene文件内容前,大家先了解些lucene的基本概念。

lucene包的文件是由很多segment文件组成的,segments_xxx文件记录了lucene包下面的segment文件数量。每个segment会包含如下的文件。

下面我们以真实的数据作为示例,看看lucene中各类型数据的容量占比。

写100w数据,有一个uuid字段,写入的是长度为36位的uuid,字符串总为3600w字节,约为35M。

数据使用一个shard,不带副本,使用默认的压缩算法,写入完成后merge成一个segment方便观察。

使用线上默认的配置,uuid存为不分词的字符串类型。创建如下索引:

首先写入100w不同的uuid,使用磁盘容量细节如下:

可以看到正排数据、倒排索引数据,列存数据容量占比几乎相同,正排数据和倒排数据还会存储Elasticsearch的唯一id字段,所以容量会比列存多一些。

35M的uuid存入Elasticsearch后,数据膨胀了3倍,达到了122.7mb。Elasticsearch竟然这么消耗资源,不要着急下结论,接下来看另一个测试结果。

我们写入100w一样的uuid,然后看看Elasticsearch使用的容量。

这回35M的数据Elasticsearch容量只有13.2mb,其中还有主要的占比还是Elasticsearch的唯一id,100w的uuid几乎不占存储容积。

所以在Elasticsearch中建立索引的字段如果基数越大(count distinct),越占用磁盘空间。

我们再看看存100w个不一样的整型会是如何。

从结果可以看到,100w整型数据,Elasticsearch的存储开销为13.6mb。如果以int型计算100w数据的长度的话,为400w字节,大概是3.8mb数据。忽略Elasticsearch唯一id字段的影响,Elasticsearch实际存储容量跟整型数据长度差不多。

我们再看一下开启最佳压缩参数对存储空间的影响:

结果中可以发现,只有正排数据会启动压缩,压缩能力确实强劲,不考虑唯一id字段,存储容量大概压缩到接近50%。

我们还做了一些实验,Elasticsearch默认是开启_all参数的,_all可以让用户传入的整体json数据作为全文检索的字段,可以更方便的检索,但在现实场景中已经使用的不多,相反会增加很多存储容量的开销,可以看下开启_all的磁盘空间使用情况:

开启_all比不开启多了40mb的存储空间,多的数据都在倒排索引上,大约会增加30%多的存储开销。所以线上都直接禁用。

然后我还做了其他几个尝试,为了验证存储容量是否和数据量成正比,写入1000w数据的uuid,发现存储容量基本为100w数据的10倍。我还验证了数据长度是否和数据量成正比,发现把uuid增长2倍、4倍,存储容量也响应的增加了2倍和4倍。在此就不一一列出数据了。

文件名为:segments_xxx

该文件为lucene数据文件的元信息文件,记录所有segment的元数据信息。

该文件主要记录了目前有多少segment,每个segment有一些基本信息,更新这些信息定位到每个segment的元信息文件。

lucene元信息文件还支持记录userData,Elasticsearch可以在此记录translog的一些相关信息。

文件后缀:.si

每个segment都有一个.si文件,记录了该segment的元信息。

segment元信息文件中记录了segment的文档数量,segment对应的文件列表等信息。

文件后缀:.fnm

该文件存储了fields的基本信息。

fields信息中包括field的数量,field的类型,以及IndexOpetions,包括是否存储、是否索引,是否分词,是否需要列存等等。

文件后缀:.fdx, .fdt

索引文件为.fdx,数据文件为.fdt,数据存储文件功能为根据自动的文档id,得到文档的内容,搜索引擎的术语习惯称之为正排数据,即doc_id ->content,es的_source数据就存在这

索引文件记录了快速定位文档数据的索引信息,数据文件记录了所有文档id的具体内容。

索引后缀:.tip,.tim

倒排索引也包含索引文件和数据文件,.tip为索引文件,.tim为数据文件,索引文件包含了每个字段的索引元信息,数据文件有具体的索引内容。

5.5.0版本的倒排索引实现为FST tree,FST tree的最大优势就是内存空间占用非常低 ,具体可以参看下这篇文章: http://www.cnblogs.com/bonelee/p/6226185.html

http://examples.mikemccandless.com/fst.py?terms=&cmd=Build+it 为FST图实例,可以根据输入的数据构造出FST图

生成的 FST 图为:

文件后缀:.doc, .pos, .pay

.doc保存了每个term的doc id列表和term在doc中的词频

全文索引的字段,会有.pos文件,保存了term在doc中的位置

全文索引的字段,使用了一些像payloads的高级特性才会有.pay文件,保存了term在doc中的一些高级特性

文件后缀:.dvm, .dvd

索引文件为.dvm,数据文件为.dvd。

lucene实现的docvalues有如下类型:

其中SORTED_SET 的 SORTED_SINGLE_VALUED类型包括了两类数据 : binary + numeric, binary是按ord排序的term的列表,numeric是doc到ord的映射。


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/bake/11633472.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-17
下一篇2023-05-17

发表评论

登录后才能评论

评论列表(0条)

    保存