350 likes | 627 Views
PostgreSQL 存储系统. 报告人:王晓方 2009/5/14. Outline. 数据库文件布局 数据库分页文件 TOAST PG 索引 日志及事务恢复. 文件布局. 数据库集群所需要的所有数据都存储在集群的数据目录里,通常用 PGDATA 来引用, PGDATA 的内容 如下表:. 文件布局. 每个表和索引都存储在独立的文件里,以该表或者该索引的 filenode 号命名。
E N D
PostgreSQL存储系统 报告人:王晓方 2009/5/14
Outline • 数据库文件布局 • 数据库分页文件 • TOAST • PG索引 • 日志及事务恢复
文件布局 • 数据库集群所需要的所有数据都存储在集群的数据目录里,通常用 PGDATA 来引用,PGDATA的内容 如下表:
文件布局 • 每个表和索引都存储在独立的文件里,以该表或者该索引的 filenode号命名。 • 在表或者索引超过 1Gb 之后,它就被分裂成一G大小的段。第一个段的文件名和 filenode 相同;随后的段名为 filenode.1,filenode.2,等等。 • 一个表如果有些字段里面可能存储相当大的数据,那么就会有个相关联的 TOAST表,用于存储无法在表的数据行中放下的太大的线外数据。 return
分页文件总体页面布局 PageHeaderData ItemPointerData ItemPointerData Free space Free space Free space Free space Items Items Items Items Items Special Space
分页文件TOAST • 因为PostgreSQL的页面大小是固定的(通常是8Kb),并且不允许元组跨越多个页面,因此不可能直接存储非常大的字段值。解决方法是允许大的字段值被压缩和/或打碎成多个物理行。 • TOAST 使用变长的长度字的最高两个二进制位作为标识位:一位表示是否被压缩;另一位表示该数值是否在线外存储(这个时候,该值剩下的部分只是一个指针,而正确的数值必须在其他地方查找)。 • 如果一个表中有任何一个字段是可以TOAST的,那么该表将有一个关联的TOAST表,其 OID 存储在表的pg_class.reltoastrelid 记录里。 • TOAST 过的属性的大的数值只是在把结果集发送给客户端的时候才抽出来(如果选择了它的话)。因此,主表要小得多,并且它的大部分行都存储在共享缓冲区里,因此就可以不需要任何线外存储。排序集也缩小了,排序将更多地在内存里完成。 return
PG索引类型 • B-tree 可以处理那些可以按照某种顺序存储的数据的等于比较和范围查询。 • R-tree用于处理多维数据上的索引。 • 散列(hash)索引只能处理简单的等于比较。 • GiST索引不是单独一种索引类型,而是一种架构,可以在这种架构上实现很多不同的索引策略。
R-TREES. A DYNAMIC INDEX STRUCTUREFOR SPATIAL SEARCHING Antonin Guttman University of Cahfornia, Berkeley 1984 ACM 0-89791-128-8/84/006/0047 $00 75
R-tree • R-tree用于有效地处理多维空间数据,其索引依据是数据的空间位置。 • 类似于B-tree, R-tree也是平衡多路搜索树,其叶子节点上存储指向实际数据的指针。 • Leaf node: (I, tuple-identifier) • Non-leaf node: (I, child-pointer)
Algorithm of R-tree • Search • Insert • Insert • SplitNode • AdjustTree • Deletion • FindLeaf • CondenseTree • Quadratic Split • PickSeeds • PickNext
R-Trees …. contd • #将记录E的矩形部分记为EI,将tuple-identifier或child-pointer记为E p Algorithm Search 考虑一棵根为T的树,查找出能够覆盖要查询矩形S的矩形所对应的索引记录。 S1 【在子树中查询】如果T不是叶子,查询每条记录来判断E I是否覆盖S,对于所有覆盖记录,调用查询算法来查询由E p指向的节点中的记录。 S2 【在叶结点中查询】如果T是个叶子,检查所有记录看EI是否覆盖了S。如果是,则E就是要查的结果
R-Trees …. contd • Algorithm Insert 将一个新的索引记录E插入到R树中 I1 【为新记录找到位置】调用ChooseLeaf找到一个叶结点L,而E就放在这个叶结点中 I2 【将记录插入叶结点中】如果叶结点还有空位,则插入。否则,调用SplitNode得到两个叶结点L和LL,LL存储着E以及L的旧记录 I3 【增殖向上传递】对L进行AdjustTree,如果有LL这也同时需要进行调整 I4 【增加深度】如过叶结点的分裂增殖导致根结点也需要分裂,则创建一个新根,而其两个孩子则是已经存在的分裂出的两个结点。
R-Trees …. contd • Algorithm ChooseLeaf 找出一个叶结点用于插入索引记录E CL1 【初始化】将N设置为根结点 CL2 【叶子检查】如果N是叶子,则返回 CL3 【选择子树】如果N不是叶子,设定一个F是N的一个目录,它 的矩形F I 是将E I包含的最小包围矩形。而正是通过选取矩形 的最小区域来解决这个关系 CL4 【从根下降直到到达叶子】将N设置为F p指向的孩子结点, 然后回到步 CL2
R-Trees …. contd • Algorithm AdjustTree 在从叶结点L上升到根节点的过程中,不断调整覆盖矩形,如果需要的话分裂节点进行增值。 AT1 【初始化】让节点N是L,如果L已经是分裂出来的,则假定NN是另一个分裂出来的节点 AT2 【检查是否完成】如果节点N是根,则结束 AT3 【在父亲记录中调整覆盖矩形】让P作为N的父节点,将N中的各个记录En放置到P中,不断调整En I使得N中的矩形能够被很好的包含 AT4【节点增殖】如果因为分裂的原因,N有一个兄弟节点NN,创建一个新的记录ENN(用ENN P指向NN)并最小包围NN的矩形。如果P有空位的话则将ENN插入进去,如P节点满的话,则将ENN和所有P的旧记录进行节点分裂 AT5【向下一层移动】将P赋值给N,如果有兄弟节点NN的话则将PP赋值给NN,回到AT2 ,重复。
R-Trees …. contd • Algorithm Quadratic Split QS1 [Pick first entry for each group] Apply PickSeeds to choose two entries to be the first elements of the groups. Assign each to a group. QS2 [Check if done] If all entries have been assigned, stop. If one group has so few entries that all the rest must be assigned to it in order for it to have the minimum number m, assign them and stop. QS3 [Select entry to assign] Invoke PickNext to choose the next entry to assign. Add it to the group whose covering rectangle will have to be enlarged least to accommodate it. Resolve ties by adding the entry to the group with smaller area, then to the one with fewer entries, then to either. Repeat from QS2
R-Trees …. contd • Algorithm PickSeeds PS1 [Calculate inefficiency of grouping entries together] For each pair of entries E1 and E2, compose a rectangle J including E1I and E2I. Calculate d=area(J)-area(E1I)-area(E2I). PS2 [Choose the most wasteful pair] Choose the pair with the largest d
R-Trees …. contd • Algorithm PickNext PN1 [Determine cost of putting each entry in each group] For each entry E not yet in a group, calculate d1=the area increase required in the covering rectangle of Group 1 to include E1. Calculate d2 similarly for Group 2. PN2 [Find entry with greatest preference for one group] Choose any entry with the maximum difference between d1 and d2 return
Generalized Search Trees J.M Hellerstein, J.F. Naughton and A. Pfeffer, “Generalized Search Trees for Database Systems,” Proc. 21st Int’l Conf. On VLDB, Sep. 1995
Generalized Search Tree (GiST) • Why GiST 不仅可以扩展索引数据的数据类型,还支持对该数据类型的查询扩展。 建立的索引可以支持符合该数据类型的本质查询,针对性较强。 以一种通用的形式整合了以往异构的索引结构。 Example B+ and R trees can be implemented as extensions to GiST. Single code base for indexing multiple dissimilar applications
GiST …. contd • Definition A GiST is a balanced multi-way tree of variable fan-out between kM and M Where k is the fill factor With the exception of the root node that can have fan-out from 2 to M Leaf nodes: (p,ptr) ptr: Identifier of some tuple of the DB Non-leaf nodes: (p,ptr) ptr: Pointer to another tree node and p: Predicate used as a search key
GiST …. contd • Properties Every node contains between kM and M index entries unless it is the root. For each index entry (p,ptr) in a leaf node, p holds for the tuple For each index entry (p,ptr) in a non-leaf node, p is true when instantiated with the values of any tuple reachable from ptr The root has at least two children unless it is a leaf All leaves appear on the same level
GiST …. contd • GiST Methods Key Methods 用户可以自己定义Key Methods,以配置GiST,这些方法包装了代表树中key值的对象类的结构和行为。 Tree Methods Tree Methods用于访问相应的key methods,由GiST实现。
GiST …. contd • GiST Key Methods … contd E is an entry of the form (p,ptr) , q is a query(一个用户查询 ), P a set of entries(一组在树的数据页上的谓词集合) Consistent(E,q) returns false if p^q guaranteed unsatisfiable, true otherwise. Union(P)合并树中的信息。给出一个条目的集合,这个函数生成一个新的谓词, 这个谓词对所有这些条目都为真 Compress(E)将数据项转换成一个适合于在一个索引页里面物理存储的格式。 Decompress(E)compress 方法的反方法。把一个数据项的索引表现形式 转换成可以由数据库操作的格式。
GiST …. contd • GiST Key Methods … contd Penalty(E1,E2):返回一个表示将新条目插入树中特定分支需要的“开销”的数值。 PickSplit(P):如果需要分裂一个页面的时候,这个函数决定页面中哪些条目保存呆旧页面里, 而哪些移动到新页面里。
GiST …. contd • GiST Tree Methods Search Controlled by the Consistent Method. Insert Controlled by the Penalty and PickSplit. Delete Controlled by the Consistent
R (p,ptr) (p,ptr) (p,ptr) (p,ptr) (p,ptr) New (q,ptr) (p,ptr) (p,ptr) (p,ptr) (p,ptr) (p,ptr) (p,ptr) (p,ptr) (q,ptr) (p,ptr) Example New (q,ptr) Penalty = m Penalty = n m < n Penalty =i Penalty = j j < i Full.. Then split according to PickSplit return
预写式日志(WAL)& 时间点的恢复(PITR) • WAL 日志存放在数据目录的 pg_xlog 目录里,它是作为一个文件段的集合存储的,通常每个段 16 MB 大。 每个段分割成多个页,通常 8K 大。 • 通常把pg_xlog目录移动到另外一个位置,然后在$PGDATA里原来的位置创建一个指向新位置的符号链接来实现。 • 在完成一个检查点并且日志文件冲刷了之后,检查点的位置保存在了文件 pg_control 里。因此在需要做恢复的时候, 后端首先读取 pg_control 和检查点记录; 然后它通过从检查点记录里标识的日志位置开始向前扫描执行 REDO 操作。 因为数据页的所有内容都保存在检查点之后的第一个页面修改的日志里, 所以自检查点以来的所有变化都将被恢复到一个一致的状态。
预写式日志(WAL)& 时间点的恢复(PITR) • PostgreSQL 提供了三种备份数据的方法: • SQL 转储(pg_dump dbname > outfile) • 文件系统级别备份(直接拷贝用于存放DB数据的文件;给数据目录做“快照”;进行文件系统备份) • 在线备份(支持即时恢复) • 设置归档WAL • 对数据库进行一次基础备份 • 必要时,从在线备份中恢复 (使用基础备份数据、归档的WAL数据及还未来得及归档的WAL数据)
预写式日志(WAL)& 时间点的恢复(PITR) • 首先,对数据库在file system level做一个backup(PostgreSQL是首先用pg_start_backup(‘label’)命令,然后用tar直接tar整个data目录,假设命名为base.tar,然后pg_stop_backup();结束热备。 • 然后,备份相关的配置文件(PostgreSQL只需备份postgresql.conf,pg_hba.conf,pg_ident.conf就可以了 • 最后,备份WAL(可以设置postgresql.conf中的archive_command, 该命令可以让PostgreSQL8自动将需要的归档的日志文件备份的其他地方中。 • 如果数据库崩溃,我们就可以使用热备产生的base.tar和archive_command产生的WAL和我们自己备份的WAL(pg_xlog)来进行数据库的recovery.