Postgres Storage
存储 # 内存 # 共享内存
本地内存
缓存
内存上下文
缓存空间管理
数据块的缓存,减少磁盘IO,有共享缓存和进程缓存
Cache
数据块之外的缓存,例如系统表
系统表缓存不会缓存整个表,是以block为单位缓存? 虚拟文件描述符
系统中文件有打开的上限,使用VFD可以突破这种限制,本质上是一个LRU缓存
空闲空间定位
快速定位磁盘中的空闲空间以插入数据
进程间通信 使用共享内存或者信号量通信
读取过程 # 从系统表中读取表的元数据信息构造元组信息 尝试从缓存读取数据 使用SMGR从磁盘读取数据到缓存中,SMGR是一个抽象层,用于实现不同存储介质的管理 SMGR和存储介质之间使用VFD来管理文件描述符,以突破系统的FD限制 标记删除,vacuum清理数据 FSM记录空闲空间 磁盘 # 表文件
SMGR
VFD
FSM
select * from pg_relation_filepath(‘idx’);
Page 结构 # 工具汇总说明
create extension pageinspect; get_raw_page(relname text, fork text, blkno int) 返回执行表的page,text指定类型,默认是main,代表普通page,使用fsm或者vm查看其他类型,可以省略 page_header(page bytea) 查看page头,输入是page数组,使用上面的函数的输出作为参数 fsm_page_contents(page bytea) returns text 查看fsm页面结构 SELECT fsm_page_contents(get_raw_page('t1', 'fsm', 0)); === HEAP相关 heap_page_items(page bytea) 查看page的具体信息 heap_tuple_infomask_flags(t_infomask integer, t_infomask2 integer) returns record 查看mask的具体含义,具体的使用方法为 SELECT * FROM heap_page_items(get_raw_page('a', 0)), LATERAL heap_tuple_infomask_flags(t_infomask, t_infomask2) WHERE t_infomask IS NOT NULL OR t_infomask2 IS NOT NULL order by lp desc; 输出为 t_infomask2 | t_infomask | t_hoff | t_bits | t_oid | t_data | raw_flags | combined_flags -------------+------------+--------+----------+-------+------------+--------------------------------------------------------------------------+---------------- 3 | 2305 | 24 | 10000000 | | \x02000000 | {HEAP_HASNULL,HEAP_XMIN_COMMITTED,HEAP_XMAX_INVALID} | {} 8195 | 1281 | 24 | 10000000 | | \x01000000 | {HEAP_HASNULL,HEAP_XMIN_COMMITTED,HEAP_XMAX_COMMITTED,HEAP_KEYS_UPDATED} | {} 主要目的是查看数据的mask的信息 === Btree相关 bt_metap(relname text) 查看btree元数据信息 bt_page_stats(relname text, blkno int) 查看btree page的统计信息 bt_page_items(relname text, blkno int) 或者 bt_page_items(page bytea) returns setof record 查看具体的信息,可以指定index或者直接使用page byte typedef struct PageHeaderData { /* XXX LSN is member of *any* block, not only page-organized ones */ PageXLogRecPtr pd_lsn; /* LSN: next byte after last byte of xlog record for last change to this page */ uint16 pd_checksum; /* checksum */ uint16 pd_flags; /* flag bits, see below */ LocationIndex pd_lower; /* offset to start of free space */ LocationIndex pd_upper; /* offset to end of free space */ LocationIndex pd_special; /* offset to start of special space */ uint16 pd_pagesize_version; TransactionId pd_prune_xid; /* oldest prunable XID, or zero if none */ ItemIdData pd_linp[FLEXIBLE_ARRAY_MEMBER]; /* line pointer array */ } PageHeaderData; void PageInit(Page page, Size pageSize, Size specialSize) { PageHeader p = (PageHeader) page; specialSize = MAXALIGN(specialSize); Assert(pageSize == BLCKSZ); Assert(pageSize > specialSize + SizeOfPageHeaderData); /* Make sure all fields of page are zero, as well as unused space */ MemSet(p, 0, pageSize); p->pd_flags = 0; p->pd_lower = SizeOfPageHeaderData; p->pd_upper = pageSize - specialSize; p->pd_special = pageSize - specialSize; PageSetPageSizeAndVersion(page, pageSize, PG_PAGE_LAYOUT_VERSION); /* p->pd_prune_xid = InvalidTransactionId; done by above MemSet */ } 大小为 pageSize,默认为8k,最开始是PageHeader,
数据库文章资源汇总
爬虫 # import requests from bs4 import BeautifulSoup prefix = 'http://mysql.taobao.org' # 获取文章名和url(文章名,url) def query_name_url(url: str): resp = requests.get(url) soup = BeautifulSoup(resp.content.decode('utf-8'), "html.parser") tags = soup.findAll('a', {'target': {'_top'}}) urls = [v for v in tags if v['href'].find('/monthly/') != -1] return [(str(v.string).strip(), prefix + v['href']) for v in urls] # 获取所有月报链接(月报名,url) def query_monthly_url(): resp = requests.get('http://mysql.taobao.org/monthly/') soup = BeautifulSoup(resp.content.decode('utf-8'), "html.parser") tags = soup.findAll('a', {'class': {'main'}}) urls = [v for v in tags if v['href'].find('/monthly/') != -1] return [(str(v.string).strip(), prefix + v['href']) for v in urls] # 获取所有文章名、URL和对应的月报链接(文章类型,文章名,url,月报名,url) def query_all_name_url(): result = [] monthly_urls = query_monthly_url() for data1 in monthly_urls: name_urls = query_name_url(data1[1]) for data2 in name_urls: result.
15445课程笔记
https://15445.courses.cs.cmu.edu/fall2021/notes/02-advancedsql.pdf
output control 控制输出结果,例如order,limit等 窗口函数 CTE Common Table Expressions,把一个语句的输出视为一张临时表参与下面的语句的运算 WITH cte1 (col1) AS (SELECT 1), cte2 (col2) AS (SELECT 2) SELECT * FROM cte1, cte2; Database Storage # 数据库的存储介质当前还是磁盘,IO慢 数据库存储要点之一是使用缓存维护数据在磁盘和内存之间的数据交换,以实现数据的快速读写 顺序读写和随机读写 顺序读写的意思是需要定位到读写的位置才能操作,例如链表。 随机读写的意思是可以直接定位到读写的位置,例如数组。 由于磁盘上随机读写速度不如顺序读写,所以当前数据库还是需要想办法使用顺序读写,例如LSM,GFS等架构都是因为这个原因导致的 磁盘和内存中数据的组织格式 # 数据全部在磁盘上,按page组织数据,内存中使用buffer pool维护缓存,磁盘中有一个page专门维护page的位置信息,使用的时候先读取此page到内存,然后 然后读取其他page到buffer pool,使用buffer pool维护page的置换情况,例如LRU,或者其他算法
可以参考lab1和slide,还是比较明显的
buffer pool中的page可以用于上层的数据运算
使用mmap可以完成类似的操作,但是实际上在使用中,如果在发生缺页中断的时候,mmap需要进行置换操作,所以会阻碍程序进程。且mmap是通用的组件,所以没有对数据库 的使用场景进行一些优化,
You never want to use mmap in your DBMS if you need to write. The DBMS (almost) always wants to control things itself and can do a better job at it since it knows more about the data being accessed and the queries being processed. The operating system is not your friend. 最好是需要什么就自己实现什么,
数据组织形式 # 文件