`

pg中的数据结构一:可扩展哈希表一

阅读更多

 二叉树搜索具有对数时间的表现有个假设:输入数据具有相当的随机性。现在我们看哈希表,这种数据结构,其在插入、删除、查询操作上也具有常数评价时间的表现,而且这种表现以统计为基础,不依赖数据的随机性。

 

我们先看看pg 里的哈希函数,再看pg 动态哈希表“dynmaic hashtable 我认为用 “可扩展哈希表” 更能体现“dynmaic hashtable ”的功能,更贴近中国人用词习惯,以后就用“可扩展哈希表”吧。 )结构、哈希表上的操作(增删查改)以及可扩展。

 

说哈希函数前先澄清一下 碰撞,碰撞根据使用的场合不同有两种情况,一是哈希函数在把普通值打散/ 计算出哈希值时可能产生的碰撞,这个需要由哈希函数本身解决,王小云教授研究的碰撞就是这个碰撞;另一个是哈希表中根据哈希键值安排哈希键所在位置时的碰撞,解决这种碰撞的方法有一次探测(linear probing )、二次探测(quadratic probing )、开链(separate chainning )等多种解决方法,pg 以开链解决这个碰撞问题。

Hash 函数:

pg hash.h 中有下列hash 函数

extern Datum hashchar(PG_FUNCTION_ARGS);

extern Datum hashint2(PG_FUNCTION_ARGS);

extern Datum hashint4(PG_FUNCTION_ARGS);

extern Datum hashint8(PG_FUNCTION_ARGS);

extern Datum hashoid(PG_FUNCTION_ARGS);

extern Datum hashenum(PG_FUNCTION_ARGS);

extern Datum hashfloat4(PG_FUNCTION_ARGS);

extern Datum hashfloat8(PG_FUNCTION_ARGS);

extern Datum hashoidvector(PG_FUNCTION_ARGS);

extern Datum hashint2vector(PG_FUNCTION_ARGS);

extern Datum hashname(PG_FUNCTION_ARGS);

extern Datum hashtext(PG_FUNCTION_ARGS);

extern Datum hashvarlena(PG_FUNCTION_ARGS);

extern Datum hash_any(register const unsigned char *k, register int keylen);

extern Datum hash_uint32(uint32 k);

   

下面这些哈希函数做将原值做一些位与或转换后,将结果作为参数调用hash_uint32 继续哈希运算

hashchar() hashint2()hashint4()hashint8()hashoid()hashenum()

下面这些哈希函数做将原值做一些位与或转换或类型转换后,将结果作为参数调用hash_any 继续哈希运算

hashfloat4 () hashfloat8 () hashoidvector () hashint2vector () hashname () hashtext () hashvarlena ()

 

这么多的哈希函数最终落到了 hash_uint32 hash_any 这两个哈希函数上,加上两个做散列的宏mix(a,b,c)final(a,b,c) 完成了哈希运算。 hash_uint32(uint32 k) hash_any(&k, sizeof(uint32)) 一样有着同样的结果,但hash_uint32 更快,并且不强制调用者把k 存储在内存中。

关于哈希函数研究,可以推荐两个人的书/ 文章看看,一个是中科院的裴定一教授,可以看他的书和文章。有优于PKICPK 标识认证专利的南湘浩教授需要哈希函数的时候就是向裴定一教授要的。南湘浩和曲延文教授以及孙玉院士(都是大牛)合作成立了QNS 工作室,我第一次路过工作室时,第一反映是这是个皮包公司,因为在租金不菲的中关村软件园里有偌大面积,但又没有几个工作人员, 后来登门拜访受教才了解内情。另一个是Bob Jenkins ,可以到他的网站 http://burtleburtle.net/bob/hash/index.html 看。或者看他们的论文。

 

可扩展哈希表可以无限增长。可扩展哈希表有一个顶层的“目录”,他的每一个入口指向ssize 个哈希桶的段的头部,最大哈希桶数是dsize * ssizedsize 是可以增大的。当然,哈希表里的记录数可以更大,但是我们不想要一个哈希桶里有很多记录或性能降是低。在共享内存中分配的哈希表时,因为他的地址是固定的,“目录”不能增大。目录的大小应该用hash_select_dirsize 选择。非共享哈希表的目录初始化大小可以是默认的。

 

可扩展哈希表和几个数据结构有关,一个是 HCTL ,这个是创建可扩展哈希表时的信息表,一个是 HTAB ,这个就是哈希表结构,一个是 HASHHDR ,这个是哈希表头结构, 包含了哈希表的所有可变信息 ,还有 HashSegment HashBucket HashElement 等结构,一个 HashSegment HashBucket 数组的头,一个 HashBucket HashElement 链表。结构定义见下面。这些结构和起来组成了可扩展哈希表。 根据pg 默认参数创建的可扩展哈希表 结构图在下面。

typedef struct HASHCTL

{

    long         num_partitions; /* # partitions (must be power of 2) */

    long         ssize;          /* segment size */

    long         dsize;          /* (initial) directory size */

    long         max_dsize;      /* limit to dsize if dir size is limited */

    long         ffactor;        /* fill factor */

    Size        keysize;        /* hash key length in bytes */

    Size        entrysize;      /* total user element size in bytes */

    HashValueFunc hash;         /* hash function */

    HashCompareFunc match;      /* key comparison function */

    HashCopyFunc keycopy;       /* key copying function */

    HashAllocFunc alloc;        /* memory allocator */

    MemoryContext hcxt;         /* memory context to use for allocations */

    HASHHDR    *hctl;           /* location of header in shared mem */

} HASHCTL;

 

struct HTAB

{

    HASHHDR    *hctl;           /* => shared control information */

    HASHSEGMENT *dir;           /* directory of segment starts */

    HashValueFunc hash;         /* hash function */

    HashCompareFunc match;      /* key comparison function */

    HashCopyFunc keycopy;       /* key copying function */

    HashAllocFunc alloc;        /* memory allocator */

    MemoryContext hcxt;         /* memory context if default allocator used */

    char        *tabname;        /* table name (for error messages) */

    bool         isshared;       /* true if table is in shared memory */

 

    /* We keep local copies of these fixed values to reduce contention */

    Size        keysize;        /* hash key length in bytes */

       long               ssize;                    /* segment size --- must be power of 2 */

       int                  sshift;                   /* segment shift = log2(ssize) */

};

struct HASHHDR

{

    /* In a partitioned table, take this lock to touch nentries or freeList */

    slock_t     mutex;          /* unused if not partitioned table */

 

    /* These fields change during entry addition/deletion */

    long         nentries;       /* number of entries in hash table */

    HASHELEMENT *freeList;      /* linked list of free elements */

 

    /* These fields can change, but not in a partitioned table */

    /* Also, dsize can't change in a shared table, even if unpartitioned */

    long         dsize;          /* directory size */

    long         nsegs;          /* number of allocated segments (<= dsize) */

    uint32      max_bucket;     /* ID of maximum bucket in use */

    uint32      high_mask;      /* mask to modulo into entire table */

    uint32      low_mask;       /* mask to modulo into lower half of table */

 

    /* These fields are fixed at hashtable creation */

    Size        keysize;        /* hash key length in bytes */

    Size        entrysize;      /* total user element size in bytes */

    long         num_partitions; /* # partitions (must be power of 2), or 0 */

    long         ffactor;        /* target fill factor */

    long         max_dsize;      /* 'dsize' limit if directory is fixed size */

    long         ssize;          /* segment size --- must be power of 2 */

    int          sshift;         /* segment shift = log2(ssize) */

    int          nelem_alloc;    /* number of entries to allocate at once */

 

#ifdef HASH_STATISTICS

 

    /*

      * Count statistics here.  NB: stats code doesn't bother with mutex, so

      * counts could be corrupted a bit in a partitioned table.

      */

    long        accesses;

    long        collisions;

#endif

};

 

typedef HASHELEMENT *HASHBUCKET;

typedef HASHBUCKET *HASHSEGMENT;

 

根据pg 默认值创建的可扩展哈希表结构图如下:

 


 

哈希表结构图

 

创建过程涉及函数及功能:

根据 info 信息和给定名字及 HashElement 元素个数进行计算创建可扩展哈希表

HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)

分配相应数目(dsize)HashSegment 数组

static bool init_htab(HTAB *hashp, long nelem)

计算给定数的以2 为底加1 取正对数值

Int my_log2(long num)

给哈希表的HashSegment 分配相应个数(ssize)HashBucket

static HASHSEGMENT seg_alloc(HTAB *hashp)

根据entry 大小计算要分的HashElement 的个数

static int choose_nelem_alloc(Size entrysize)

分配HashElement+Entry 并加入到HASHHDRfreelist 链表

static bool element_alloc(HTAB *hashp, int nelem)

哈希表的销毁:

主要是调用MemoryContextDelete(hashp->hcxt) (参见《pg 内存管理机制三》)销毁哈希表

Void hash_destroy(HTAB *hashp)

 

创建流程图如下:

 


创建可扩展哈希表流程图

上图中红色框主要是根据条件设置 HTAB 结构类型变量的各成员,右边黄色框中主要是计算 HashSegment HashBucket 以及 HashElement 成员的数目并为它们分配内存。

就到这儿吧。

 

  • 大小: 96.9 KB
  • 大小: 207.9 KB
0
1
分享到:
评论

相关推荐

    PG 入门教程学习pg

    同时,PG有强大的复制和集群解决方案,如流复制、逻辑复制等,能保证数据的高可用性和可扩展性。 学习过程中,可以参考PostgreSQL的手册,这是一份详尽的官方文档,涵盖了所有功能和用法。手册的中文版也有热心的...

    PostgreSQL 9 从零开始学.pdf

    PostgreSQL,简称PG,是一种强大的开源关系数据库管理系统,具有高度的稳定性和可扩展性。本教程“PostgreSQL 9 从零开始学”旨在帮助初学者理解并掌握这个系统的核心概念和操作。PostgreSQL 9是其9.x系列的一个版本...

    PostgresSQL优化

    1. 选择合适的索引类型:B-Tree索引适用于大多数情况,哈希索引用于等值查询,Gin和GiST索引适用于全文搜索和复杂数据结构。 2. 创建复合索引:根据查询模式创建包含多个字段的索引,以提高查询效率。 3. 避免过多...

    PostgreSQL 9.5文档pdf版

    PostgreSQL,简称pg,是一种开源的对象关系型数据库管理系统(ORDBMS),因其强大的功能、高度的可扩展性和稳定性而受到全球开发者的广泛青睐。PostgreSQL 9.5是该系统的一个重要版本,它在前一版本的基础上引入了...

    PostgreSQL从入门到精通.rar

    视图可以简化复杂的查询,提供安全性,以及隐藏底层数据结构。 2. **索引**:PostgreSQL支持多种类型的索引,包括B树、哈希、GiST(通用迭代搜索树)、SP-GiST(空间优先搜索树)等,提高查询速度。 3. **触发器**...

    postgresql 8.2.3 中文文档.CHM

    PostgreSQL 8.2.3 是一款开源的关系型数据库管理系统,以其强大、稳定和高度可扩展性而闻名。这个版本的中文文档以CHM(Compiled Help Manual)格式提供,是学习和理解PostgreSQL 8.2.3功能、操作和查询语言的重要...

    PostgreSQL基础教程.rar_postgresql

    2. **表结构设计**:使用`CREATE TABLE`定义表的字段、数据类型、主键和外键约束,例如`CREATE TABLE employees (id SERIAL PRIMARY KEY, name VARCHAR(50));` ### 四、SQL查询语句 1. **SELECT语句**:用于查询...

    Postgresql编程教程(自学).docx_postgresql_

    它的主要特点是高度可扩展性,支持复杂查询,以及遵循ACID(原子性、一致性、隔离性和持久性)原则。 ### 2. 安装与配置 在开始编程之前,你需要在你的计算机上安装PostgreSQL。教程将指导你如何在Windows、Linux或...

    postgresql速查表

    2. **存储过程**:一组可重用的SQL语句,封装为一个命名实体,提高代码复用和性能。 **八、安全性与权限** PostgreSQL 提供了细粒度的权限系统,包括用户、角色、对象权限等。GRANT和REVOKE语句用来分配和撤销权限...

    PostgreSQL数据库内核分析

    - **复杂类型**: 支持数组、哈希、JSON、XML等复杂数据结构。 - **自定义类型**: 用户可以定义自己的数据类型,扩展数据库功能。 5. **安全性与权限** - **角色与用户**: 角色可以拥有权限,用户是角色的实例,...

    postgresql-10.13-1-windows-x64-binaries.zip

    总之,PostgreSQL 10.13.1提供了强大的数据库管理功能和高度的可扩展性,无论是小型项目还是大型企业级应用,都能找到适合的解决方案。通过深入理解和熟练掌握其特性和操作,你将能更好地利用这个优秀的数据库系统。

    postgersql中文手册

    PostgreSQL,通常简称为 Postgres,是一款强大的开源关系型数据库管理系统,以其稳定性、可扩展性和强大的SQL支持而备受赞誉。PostgreSQL 8.2.3是该系统的某一版本,虽然现在已经有了更新的版本,但这个版本的手册...

    postgresql文档fz群.rar

    1. **对象关系模型**:PostgreSQL支持传统的SQL数据类型以及对象-关系特性,如继承、多态性、类型系统和自定义数据类型,这使得它在处理复杂的数据结构和应用程序时具有优势。 2. **事务一致性**:PostgreSQL保证了...

    PostgreSQL日常维护、监控、排错、优化.pdf

    - **进程维护**:监控并管理内存使用情况,防止哈希表等资源被过度占用。 - **序列耗尽维护**:监控序列使用情况,及时重置或增加序列范围。 - **冷热分离**:通过分区等方式将热点数据与冷数据分开存储,提高查询...

    postgresql源代码

    PostgreSQL是一种开源的对象关系型数据库管理系统(ORDBMS),它以其强大的功能、高度的可扩展性和稳定性而闻名。本文将深入探讨"postgresql-8.0.23.tar.gz"源代码包中的关键知识点。 首先,"postgresql-8.0.23...

    cpp-PostgreSQL中文手册翻译计划

    PostgreSQL是一种强大的开源关系型数据库管理系统,以其高度的稳定性、安全性及可扩展性而受到全球开发者的广泛赞誉。官方手册是了解和掌握PostgreSQL技术的关键资源,它详尽地涵盖了从安装配置到高级查询、性能优化...

    PostgreSQL实用实例

    二、数据类型与表结构 PostgreSQL支持多种数据类型,包括基本类型(如整数、浮点数、字符串、布尔值)以及复杂类型(如数组、JSON、XML)。创建表时,可以定义字段的数据类型、主键、外键和约束条件。例如: ```sql...

    Greenplum企业应用实战 PDF电子书下载 带书签目录 完整版.pdf

    - **定义与历史**:Greenplum是一款高度可扩展的企业级数据仓库解决方案,由Greenplum公司开发,后被EMC收购,目前归属于戴尔科技集团。它采用MPP(大规模并行处理)架构,能够高效地存储和分析海量数据。 - **核心...

    MySQL和PostgreSQL的比较

    - PostgreSQL 通过 `postmaster` 进程(通过 `pg_ctl` 启动)启动实例,一个实例管理一个或多个数据库组成的集群,集群由一个目录结构管理,所有数据都存储在这个目录中。 2. **数据库管理**: - MySQL 的数据库...

    postgresql-v12.1.zip

    2. **改进的索引**:在这一版本中,B树索引的结构得到了优化,支持更多的索引类型,例如,哈希索引的性能有所提升,同时引入了GIN(Generalized Inverted Indexes)和GiST(Generalized Search Tree)的并行构建,...

Global site tag (gtag.js) - Google Analytics