- 论坛徽章:
- 0
|
InnoDB将所有记录存储在一个确定大小的单元中,也就是页(有时候也称为块)。目前所有页的大小都是固定的16K。
一个页包含有很多记录,另外也包含Headers和Trailer。下面我们从总体结构上来看看页的组成。
一个页包含七个部分
Fil Header
Page Header
Infimum + Supremum Records
User Records
Free Space
Page Directory
Fil Trailer
我们可以看到,一个页包含两对header/trailer。里面的一对,Page Header和Page Directory主要涉及到\page program group,外面的一对Fil Header和Fil Trailer主要涉及到\fil program group。Fil Header也被称为File Page Header。
夹在headers和trailers中间的就是一些记录和自由(未使用)空间。一个页通常开始于两个固定的记录,称为Infirmum和Supremum,然后就是用户记录。在用户记录和page directory中间是自由空间,用来存放新的记录。
Fil Header
Fil Header由八个部分组成:
Name Size Remarks
FIL_PAGE_SPACE 4 4 ID of the space the page is in
FIL_PAGE_OFFSET 4 ordinal page number from start of space
FIL_PAGE_PREV 4 offset of previous page in key order
FIL_PAGE_NEXT 4 offset of next page in key order
FIL_PAGE_LSN 8 log serial number of page's latest log record
FIL_PAGE_TYPE 2 current defined types are: FIL_PAGE_INDEX, FIL_PAGE_UNDO_LOG, FIL_PAGE_INODE, FIL_PAGE_IBUF_FREE_LIST
FIL_PAGE_FILE_FLUSH_LSN 8 "the file has been flushed to disk at least up to this lsn" (log serial number), valid only on the first page of the file
FIL_PAGE_ARCH_LOG_NO 4 the latest archived log file number at the time that FIL_PAGE_FILE_FLUSH_LSN was written (in the log)
FIL_PAGE_SPACE是一个很重要的标识符,因为不同的页可能属于同一文件中不同的空间。
空间可能指的是log或表空间。
FIL_PAGE_PREV和FIL_PAGE_NEXT是页的前后指针,用来指向前一个页和后一个页。
FIL_PAGE_FILE_FLUSH_LSN, FIL_PAGE_PREV和FIL_PAGE_NEXT都和日志相关。
FIL_PAGE_FILE_FLUSH_LSN 和FIL_PAGE_ARCH_LOG_NO只在数据文件的第一页有效。
Page Header
Page Header由14个部分组成:
Name Size Remarks
PAGE_N_DIR_SLOTS 2 number of directory slots in the Page Directory part; initial value = 2
PAGE_HEAP_TOP 2 record pointer to first record in heap
PAGE_N_HEAP 2 number of heap records; initial value = 2
PAGE_FREE 2 record pointer to first free record
PAGE_GARBAGE 2 "number of bytes in deleted records"
PAGE_LAST_INSERT 2 record pointer to the last inserted record
PAGE_DIRECTION 2 either PAGE_LEFT, PAGE_RIGHT, or PAGE_NO_DIRECTION
PAGE_N_DIRECTION 2 number of consecutive inserts in the same direction, e.g. "last 5 were all to the left"
PAGE_N_RECS 2 number of user records
PAGE_MAX_TRX_ID 8 the highest ID of a transaction which might have changed a record on the page (only set for secondary indexes)
PAGE_LEVEL 2 level within the index (0 for a leaf page)
PAGE_INDEX_ID 8 identifier of the index the page belongs to
PAGE_BTR_SEG_LEAF 10 "file segment header for the leaf pages in a B-tree" (this is irrelevant here)
PAGE_BTR_SEG_TOP 10 "file segment header for the non-leaf pages in a B-tree" (this is irrelevant here)
PAGE_FREE:
被free掉的记录都存在一个单向链表中,PAGE_FREE指针指向这个链表的第一条记录。下一条记录通过记录的EXTRA BYTES来指示。
PAGE_DIRECTION和PAGE_N_DIRECTION:
用来指示记录是否以升序的形式插入。
PAGE_HEAP_TOP和PAGE_FREE以及PAGE_LAST_INSERT:
和记录指针一样,这些指针也不是指向记录的开始,而是记录的原点(见记录格式)。
PAGE_BTR_SEG_LEAF和PAGE_BTR_SEG_TOP:
这几个域保存了索引节点的文件段信息(space ID, page number, byte offset)。InnoDB使用这些信息来分配一个新的页。InnoDB为叶子页和内节点页分别分配空间。
Infimum和Supremum记录
在InnoDB中一个Infimum就相当于达梦中的最小虚记录,它比任何可能的实际值都要小,一个Supremum记录相当于达梦中的最大虚记录,它比任何可能的实际值都要大。InnoDB在页创建的时候将自动创建Infimum记录和Supremum记录,这两个记录为页中记录的遍历提供了一个屏障。而且infimum记录对于临时记录锁也有用。
User Records
在User Records部分,你可以找到用户插入的所有记录。
有两种办法可以遍历用户记录,取决于你是要考虑组织顺序还是不考虑。
一个无序的链表通常称为heap,InnoDB插入一条新的记录不会按照B树键的顺序来插入,而是在现在的行的最后插入,或者从删除的行上分配空间。
但是根据B树的定义,记录的存取应该是按照关键字来排序的,因此,每个记录都有一个指针(EXTRA BYTES中的next域)来指向按照关键字排序的下一个记录。也就是说,这些记录是一个单向链表。
Page Directory
Page Directory是指向记录的指针。有时候这些记录指针被称为slots或directory solts。InnoDB并不为页中的每个记录保留一个slot,而是使用一个稀疏目录,在一个完整的页中,每六个记录使用一个slot。
slots记录了记录的逻辑顺序。如果记录物理格式为A B F D,那么slots中为A B D F。
但是因为Page Directory并不为每个记录保留一个slot,因此,它只能给出一个大体的位置,然后利用记录的next指针。
Fil Trailer
Fil Trailer只有一个部分:
FIL_PAGE_END_LSN 8 low 4 bytes = checksum of page, last 4 bytes = same as FIL_PAGE_LSN
这个部分是用来保证页的完整性的。
下面看你个完整的例子:
这是一个页在物理上的存储,
Address Values in Hexadecimal Values in ASCII
0D4000: 00 00 00 00 00 00 00 35 FF FF FF FF FF FF FF FF .......5........
0D4010: 00 00 00 00 00 00 E2 64 45 BF 00 00 00 00 00 00 .......dE.......
0D4020: 00 00 00 00 00 00 00 05 02 F5 00 12 00 00 00 00 ................
0D4030: 02 E1 00 02 00 0F 00 10 00 00 00 00 00 00 00 00 ................
0D4040: 00 00 00 00 00 00 00 00 00 14 00 00 00 00 00 00 ................
0D4050: 00 02 16 B2 00 00 00 00 00 00 00 02 15 F2 08 01 ................
0D4060: 00 00 03 00 89 69 6E 66 69 6D 75 6D 00 09 05 00 .....infimum....
0D4070: 08 03 00 00 73 75 70 72 65 6D 75 6D 00 22 1D 18 ....supremum."..
0D4080: 13 0C 06 00 00 10 0D 00 B7 00 00 00 00 04 14 00 ................
0D4090: 00 00 00 09 1D 80 00 00 00 2D 00 84 41 41 41 41 .........-..AAAA
0D40A0: 41 41 41 41 41 41 41 41 41 41 41 1F 1B 17 13 0C AAAAAAAAAAA.....
...
...
0D7FE0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 74 ...............t
0D7FF0: 02 47 01 AA 01 0A 00 65 3A E0 AA 71 00 00 E2 64 .G.....e:..q...d
我们去掉前面38字节的Fil Header。Page Header开始位置是0d4026,如下所示:
Location Name Description
00 05 PAGE_N_DIR_SLOTS There are 5 directory slots.
02 F5 PAGE_HEAP_TOP At location 0402F5, not shown, is the beginning of free space. Maybe a better name would have been PAGE_HEAP_END.
00 12 PAGE_N_HEAP There are 18 (hexadecimal 12) records in the page.
00 00 PAGE_FREE There are zero free (deleted) records.
00 00 PAGE_GARBAGE There are zero bytes in deleted records.
02 E1 PAGE_LAST_INSERT The last record was inserted at location 02E1, not shown, within the page.
00 02 PAGE_DIRECTION A glance at page0page.h will tell you that 2 is the #defined value for PAGE_RIGHT.
00 0F PAGE_N_DIRECTION The last 15 (hexadecimal 0F) inserts were all done "to the right" because I was inserting in ascending order.
00 10 PAGE_N_RECS There are 16 (hexadecimal 10) user records. Notice that PAGE_N_RECS is smaller than the earlier field, PAGE_N_HEAP.
00 00 00 00 00 00 00 PAGE_MAX_TRX_ID
00 00 PAGE_LEVEL Zero because this is a leaf page.
00 00 00 00 00 00 00 14 PAGE_INDEX_ID This is index number 20.
00 00 00 00 00 00 00 02 16 B2 PAGE_BTR_SEG_LEAF
00 00 00 00 00 00 00 02 15 F2 PAGE_BTR_SEG_TOP |
|