MySQL Innodb 저장 구조 및 저장 Null 값 용법 상세 설명

배경:
표 공간:INNODB 의 모든 데 이 터 는 표 공간 에 존재 합 니 다(공유 표 공간).innodb 를 열 면file_per_table,모든 표 의 데 이 터 는 하나의 표 공간 에 저 장 됩 니 다(표 공간 을 독점 합 니 다).
테이블 공간 은 데이터,색인,캐 시 삽입,데이터 사전 을 포함 합 니 다.공유 표 공간 은 Undo 정보(<물리 공간 상>을 회수 하지 않 음),더 블 캐 시 정보,사무 정보 등 을 포함한다.
세그먼트(segment):표 공간 을 구성 하고 구역 으로 구성 합 니 다.
구역(extent):64 개의 연속 페이지 로 구성 되 어 있 습 니 다.페이지 당 16K,총 1M.빅 데이터 세그먼트 에 대해 서 는 마지막 마다 4 개 구역 을 신청 할 수 있다.
페이지(page):INNODB 디스크 관리 단위 로 줄 로 구성 되 어 있 습 니 다.
줄(row):사무 ID,스크롤 백 포인터,열 정보 등 을 포함 합 니 다.
목적 1:
표 공간의 각 페이지 의 정보 와 넘 치 는 줄 데이터 에 저 장 된 정 보 를 알 아 보 세 요.이 책의 저자 장 승 요 를 통 해 작 성 된 도구:http://code.google.com/p/david-mysql-tools/source/browse/trunk/py_innodb_page_type/
3 개의 스 크 립 트:
py_innodb_page_info.py

View Code 

#! /usr/bin/env python 
#encoding=utf-8
import mylib
from sys import argv
from mylib import myargv

if __name__ == '__main__':
 myargv = myargv(argv)
 if myargv.parse_cmdline() == 0:
  pass
 else:
  mylib.get_innodb_page_type(myargv)
mylib.py

View Code 

encoding=utf-8
import os
import include
from include import *

TABLESPACE_NAME='D:\\mysql_data\\test\\t.ibd'
VARIABLE_FIELD_COUNT = 1
NULL_FIELD_COUNT = 0

class myargv(object):
 def __init__(self, argv):
  self.argv = argv
  self.parms = {}
  self.tablespace = ''

 def parse_cmdline(self):
  argv = self.argv
  if len(argv) == 1:
   print 'Usage: python py_innodb_page_info.py [OPTIONS] tablespace_file'
   print 'For more options, use python py_innodb_page_info.py -h'
   return 0
  while argv:
   if argv[0][0] == '-':
    if argv[0][1] == 'h':
     self.parms[argv[0]] = ''
     argv = argv[1:]
     break
    if argv[0][1] == 'v':
     self.parms[argv[0]] = ''
     argv = argv[1:]
    else:
     self.parms[argv[0]] = argv[1]
     argv = argv[2:]
   else:
    self.tablespace = argv[0]
    argv = argv[1:]
  if self.parms.has_key('-h'):
   print 'Get InnoDB Page Info'
   print 'Usage: python py_innodb_page_info.py [OPTIONS] tablespace_file
' print 'The following options may be given as the first argument:' print '-h help ' print '-o output put the result to file' print '-t number thread to anayle the tablespace file' print '-v verbose mode' return 0 return 1 def mach_read_from_n(page,start_offset,length): ret = page[start_offset:start_offset+length] return ret.encode('hex') def get_innodb_page_type(myargv): f=file(myargv.tablespace,'rb') fsize = os.path.getsize(f.name)/INNODB_PAGE_SIZE ret = {} for i in range(fsize): page = f.read(INNODB_PAGE_SIZE) page_offset = mach_read_from_n(page,FIL_PAGE_OFFSET,4) page_type = mach_read_from_n(page,FIL_PAGE_TYPE,2) if myargv.parms.has_key('-v'): if page_type == '45bf': page_level = mach_read_from_n(page,FIL_PAGE_DATA+PAGE_LEVEL,2) print "page offset %s, page type <%s>, page level <%s>"%(page_offset,innodb_page_type[page_type],page_level) else: print "page offset %s, page type <%s>"%(page_offset,innodb_page_type[page_type]) if not ret.has_key(page_type): ret[page_type] = 1 else: ret[page_type] = ret[page_type] + 1 print "Total number of page: %d:"%fsize for type in ret: print "%s: %s"%(innodb_page_type[type],ret[type])
include.py

View Code 

#encoding=utf-8
INNODB_PAGE_SIZE = 16*1024*1024

# Start of the data on the page
FIL_PAGE_DATA = 38


FIL_PAGE_OFFSET = 4 # page offset inside space
FIL_PAGE_TYPE = 24 # File page type

# Types of an undo log segment */
TRX_UNDO_INSERT = 1
TRX_UNDO_UPDATE = 2

# On a page of any file segment, data may be put starting from this offset
FSEG_PAGE_DATA = FIL_PAGE_DATA

# The offset of the undo log page header on pages of the undo log
TRX_UNDO_PAGE_HDR = FSEG_PAGE_DATA

PAGE_LEVEL = 26 #level of the node in an index tree; the leaf level is the level 0 */

innodb_page_type={
 '0000':u'Freshly Allocated Page',
 '0002':u'Undo Log Page',
 '0003':u'File Segment inode',
 '0004':u'Insert Buffer Free List',
 '0005':u'Insert Buffer Bitmap',
 '0006':u'System Page',
 '0007':u'Transaction system Page',
 '0008':u'File Space Header',
 '0009':u'     ',
 '000a':u'Uncompressed BLOB Page',
 '000b':u'1st compressed BLOB Page',
 '000c':u'Subsequent compressed BLOB Page',
 '45bf':u'B-tree Node'
 }

innodb_page_direction={
 '0000': 'Unknown(0x0000)',
 '0001': 'Page Left',
 '0002': 'Page Right',
 '0003': 'Page Same Rec',
 '0004': 'Page Same Page',
 '0005': 'Page No Direction',
 'ffff': 'Unkown2(0xffff)'
}


INNODB_PAGE_SIZE=1024*16 # InnoDB Page 16K
테스트 1:

root@localhost : test 02:26:13>create table tt(id int auto_increment,name varchar(10),age int,address varchar(20),primary key (id))engine=innodb;
Query OK, 0 rows affected (0.17 sec)
root@zhoujy:/var/lib/mysql/test# ls -lh tt.ibd 
-rw-rw---- 1 mysql mysql 96K 2012-10-17 14:26 tt.ibd
ibd 보기:

root@zhoujy:/home/zhoujy/jiaoben/read_ibd# python py_innodb_page_info.py /var/lib/mysql/test/tt.ibd -v
page offset 00000000, page type <File Space Header>
page offset 00000001, page type <Insert Buffer Bitmap>
page offset 00000002, page type <File Segment inode>
page offset 00000003, page type <B-tree Node>, page level <0000> ---    
page offset 00000000, page type <Freshly Allocated Page>
page offset 00000000, page type <Freshly Allocated Page>
Total number of page: 6: 
Freshly Allocated Page: 2
Insert Buffer Bitmap: 1
File Space Header: 1
B-tree Node: 1
File Segment inode: 1
설명:
총 페이지 수:총 페이지 수
새로 할 당 된 페이지:사용 가능 한 페이지
Buffer Bitmap 삽입:캐 시 비트 맵 페이지 삽입
Buffer 무료 목록 삽입:캐 시 남 은 목록 페이지 삽입
B-tree 노드:데이터 페이지
Uncompressed BLOB 페이지:바 이 너 리 대상 페이지,넘 치 는 줄 을 저장 하 는 페이지,즉 넘 치 는 페이지
위 에서 얻 은 정 보 는 표 초기 화 크기 가 96K 이 고 Total number of page*16 에서 얻 은 것 입 니 다.데이터 페이지 1 개,사용 가능 한 페이지 2 개.

root@localhost : test 02:42:58>insert into tt values(name,age,address) values('aaa',23,'HZZZ');
의혹:왜 신청 구역 이 없 습 니까?구역 은 64 개의 연속 페이지 이 고 크기 는 1M 이다.그럼 시계 크기 도 최소 1m 는 돼 야 지.하지만 지금 은 96K(기본 값)밖 에 없다.각 단락 이 시 작 될 때 32 페이지 크기 의 조각 페이지 에 데 이 터 를 저장 하고 사용 하기 때문이다.
완 료 된 후에 야 64 페이지 의 연속 신청 으로 최대 4 개 구역 을 신청 하여 데이터 의 순 서 를 보증 할 수 있다.여기 서 표 크기 증 가 는 최소 64 페이지 크기 의 공간 에 따라 증가 하 는 것 으로 나 타 났 다.즉,1M 증가 이다.
인증:
데 이 터 를 채 우 고 이 32 개의 조각 페이지 를 채 우 고 32*16=512 K.1M 이상 의 공간 을 신청 할 수 있 는 지 살 펴 보 자.

View Code 

root@zhoujy:/home/zhoujy/jiaoben/read_ibd# ls -lh /var/lib/mysql/test/tt.ibd 
-rw-rw---- 1 mysql mysql 576K 2012-10-17 15:30 /var/lib/mysql/test/tt.ibd
root@zhoujy:/home/zhoujy/jiaoben/read_ibd# python py_innodb_page_info.py /var/lib/mysql/test/tt.ibd -v
page offset 00000000, page type <File Space Header>
page offset 00000001, page type <Insert Buffer Bitmap>
page offset 00000002, page type <File Segment inode>
page offset 00000003, page type <B-tree Node>, page level <0001>
page offset 00000004, page type <B-tree Node>, page level <0000>
page offset 00000005, page type <B-tree Node>, page level <0000>
page offset 00000006, page type <B-tree Node>, page level <0000>
page offset 00000007, page type <B-tree Node>, page level <0000>
page offset 00000008, page type <B-tree Node>, page level <0000>
page offset 00000009, page type <B-tree Node>, page level <0000>
page offset 0000000a, page type <B-tree Node>, page level <0000>
page offset 0000000b, page type <B-tree Node>, page level <0000>
page offset 0000000c, page type <B-tree Node>, page level <0000>
page offset 0000000d, page type <B-tree Node>, page level <0000>
page offset 0000000e, page type <B-tree Node>, page level <0000>
page offset 0000000f, page type <B-tree Node>, page level <0000>
page offset 00000010, page type <B-tree Node>, page level <0000>
page offset 00000011, page type <B-tree Node>, page level <0000>
page offset 00000012, page type <B-tree Node>, page level <0000>
page offset 00000013, page type <B-tree Node>, page level <0000>
page offset 00000014, page type <B-tree Node>, page level <0000>
page offset 00000015, page type <B-tree Node>, page level <0000>
page offset 00000016, page type <B-tree Node>, page level <0000>
page offset 00000017, page type <B-tree Node>, page level <0000>
page offset 00000018, page type <B-tree Node>, page level <0000>
page offset 00000019, page type <B-tree Node>, page level <0000>
page offset 0000001a, page type <B-tree Node>, page level <0000>
page offset 0000001b, page type <B-tree Node>, page level <0000>
page offset 0000001c, page type <B-tree Node>, page level <0000>
page offset 0000001d, page type <B-tree Node>, page level <0000>
page offset 0000001e, page type <B-tree Node>, page level <0000>
page offset 0000001f, page type <B-tree Node>, page level <0000>
page offset 00000020, page type <B-tree Node>, page level <0000>
page offset 00000021, page type <B-tree Node>, page level <0000>
page offset 00000022, page type <B-tree Node>, page level <0000>
page offset 00000023, page type <B-tree Node>, page level <0000>
Total number of page: 36:
Insert Buffer Bitmap: 1
File Space Header: 1
B-tree Node: 33
File Segment inode: 1
"추가"페이지:4 개
page offset 00000000,page type:파일 헤더 공간 페이지
page offset 0000001,page type<삽입 버퍼 비트 맵>:캐 시 비트 맵 페이지 삽입
page offset 0000002,page type:파일 세그먼트 노드
page offset 0000003,page type,page level<0001>:루트 페이지
조각 페이지:32 개
page type , page level <0000>
총 36 페이지,ibd 크기 576 K 의 유래:32*16=512 K(조각 페이지)+4*16=64(추가 페이지),여기 서 다시 삽입 하려 면 최소 1M 페이지 를 신청 해 야 합 니 다.

root@zhoujy:/home/zhoujy/jiaoben/read_ibd# ls -lh /var/lib/mysql/test/tt.ibd 
-rw-rw---- 1 mysql mysql 2.0M 2012-10-17 16:10 /var/lib/mysql/test/tt.ibd
root@zhoujy:/home/zhoujy/jiaoben/read_ibd# python py_innodb_page_info.py /var/lib/mysql/test/tt.ibd
Total number of page: 128:
Freshly Allocated Page: 91
Insert Buffer Bitmap: 1
File Space Header: 1
B-tree Node: 34
File Segment inode: 1
페이지 는 36 에서 128 로 뛰 었 다.이미 32 개의 조각 페이지 를 다 썼 기 때문에 새로운 페이지 는 구역 방식 으로 공간 신청 을 할 것 이다.정보 에서 사용 가능 한 페이지 가 많은 것 을 보 았 는데,바로 이 점 을 설명 한다.
▲넘 치 는 줄 데이터 저장:INNODB 저장 엔진 은 페이지 당 최소 두 줄 의 기록 이 있 는 색인 조직 이기 때문에 페이지 에 한 줄 의 기록 만 저장 할 수 있다 면 INNODB 는 자동 으로 넘 치 는 페이지 에 줄 데 이 터 를 넣 습 니 다.넘 침 줄 이 발생 했 을 때 실제 데 이 터 는 BLOB 페이지 에 저장 되 고 데이터 페이지 는 데이터 의 이전 768 바이트(오래된 파일 형식)만 저장 되 며 새로운 파일 형식(Barracuda)은 완전히 넘 침 방식 으로 데이터 페이지 는 20 바이트 의 지침 만 저장 되 며 BLOB 도 있 는 데 이 터 를 저장 합 니 다.어떻게 표 에 넘 치 는 줄 의 데 이 터 를 봅 니까?

root@localhost : test 04:52:34>create table t1 (id int,name varchar(10),memo varchar(8000))engine =innodb default charset utf8;
Query OK, 0 rows affected (0.16 sec)

root@localhost : test 04:53:10>insert into t1 values(1,'zjy',repeat(' ',8000));
Query OK, 1 row affected (0.00 sec)
ibd 보기:

root@zhoujy:/home/zhoujy/jiaoben/read_ibd# python py_innodb_page_info.py /var/lib/mysql/test/t1.ibd -v
page offset 00000000, page type <File Space Header>
page offset 00000001, page type <Insert Buffer Bitmap>
page offset 00000002, page type <File Segment inode>
page offset 00000003, page type <B-tree Node>, page level <0000>
page offset 00000004, page type <Uncompressed BLOB Page>
page offset 00000005, page type <Uncompressed BLOB Page>
Total number of page: 6:
Insert Buffer Bitmap: 1
Uncompressed BLOB Page: 2
File Space Header: 1
B-tree Node: 1
File Segment inode: 1
정보 에서 보 듯 이 방금 삽 입 된 한 줄 의 기록 이 넘 쳐 2 개의 BLOB 페이지 에 저장 되 었 습 니 다().1 페이지 가 16K 에 불과 하고 2 줄 의 데 이 터 를 저장 해 야 하기 때문에 줄 당 기록 은 8K 보다 작 으 면 좋 고 위의 것 은 8K 보다 훨씬 커서 넘 쳤 다.물론 이것 도 큰 필드 를 포함 하 는 것 이 아 닙 니 다.만약 에 표 안에 5 개의 필드 가 모두 varchar(512)[여러 개의 varchar 의 총 화 는 8K 이상 이면 됩 니 다]도 넘 칠 수 있 습 니 다.

root@localhost : test 05:08:39>create table t2 (id int,name varchar(1000),address varchar(512),company varchar(200),xx varchar(512),memo varchar(512),dem varchar(1000))engine =innodb default charset utf8;
Query OK, 0 rows affected (0.17 sec)
root@localhost : test 05:08:43>insert into t2 values(1,repeat(' ',1000),repeat(' ',500),repeat(' ',500),repeat(' ',500),repeat(' ',500),repeat(' a',500));
1000+500+500+500+500+500=3500*3>8000 바이트;길드 넘 침:

root@zhoujy:/home/zhoujy/jiaoben/read_ibd# python py_innodb_page_info.py /var/lib/mysql/test/t2.ibd -v
page offset 00000000, page type <File Space Header>
page offset 00000001, page type <Insert Buffer Bitmap>
page offset 00000002, page type <File Segment inode>
page offset 00000003, page type <B-tree Node>, page level <0000>
page offset 00000004, page type <Uncompressed BLOB Page>
page offset 00000000, page type <Freshly Allocated Page>
Total number of page: 6:
Insert Buffer Bitmap: 1
Freshly Allocated Page: 1
File Segment inode: 1
B-tree Node: 1
File Space Header: 1
Uncompressed BLOB Page: 1
페이지 에 실제 데 이 터 를 저장 합 니 다.그 데이터 페이지 는 도대체 무엇 을 저장 합 니까?hexdump 로 보기:

root@zhoujy:/home/zhoujy/jiaoben/read_ibd# hexdump -C -v /var/lib/mysql/test/t1.ibd > t1.txt
ibd 보기:

View Code 

3082 0000c090 00 32 01 10 80 00 00 01 7a 6a 79 e6 88 91 e6 88 |.2......zjy.....|
3083 0000c0a0 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 |................|
3084 0000c0b0 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 |................|
3085 0000c0c0 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 |................|
3086 0000c0d0 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 |................|
3087 0000c0e0 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 |................|
3088 0000c0f0 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 |................|
3089 0000c100 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 |................|
3090 0000c110 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 |................|
3091 0000c120 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 |................|
3092 0000c130 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 |................|
3093 0000c140 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 |................|
3094 0000c150 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 |................|
3095 0000c160 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 |................|
3096 0000c170 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 |................|
3097 0000c180 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 |................|
3098 0000c190 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 |................|
3099 0000c1a0 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 |................|
3100 0000c1b0 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 |................|
3101 0000c1c0 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 |................|
3102 0000c1d0 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 |................|
3103 0000c1e0 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 |................|
3104 0000c1f0 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 |................|
3105 0000c200 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 |................|
3106 0000c210 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 |................|
3107 0000c220 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 |................|
3108 0000c230 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 |................|
3109 0000c240 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 |................|
3110 0000c250 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 |................|
3111 0000c260 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 |................|
3112 0000c270 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 |................|
3113 0000c280 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 |................|
3114 0000c290 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 |................|
3115 0000c2a0 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 |................|
3116 0000c2b0 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 |................|
3117 0000c2c0 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 |................|
3118 0000c2d0 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 |................|
3119 0000c2e0 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 |................|
3120 0000c2f0 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 |................|
3121 0000c300 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 |................|
3122 0000c310 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 |................|
3123 0000c320 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 |................|
3124 0000c330 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 |................|
3125 0000c340 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 |................|
3126 0000c350 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 |................|
3127 0000c360 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 |................|
3128 0000c370 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 |................|
3129 0000c380 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 |................|
3130 0000c390 88 91 e6 88 91 e6 88 91 e6 88 91 00 00 02 1c 00 |................|
텍스트 중 마침 48 줄 이 고 줄 당 16 바이트 입 니 다.48*16=768 바이트,데이터 페이지 는 데이터 만 저장 하 는 이전 768 바이트(오래된 파일 형식)를 마침 검증 했다.
총화 1:
위의 정 보 를 통 해 ibd 표 공간의 각 페이지 의 분포 와 이용 정보 와 표 공간의 크기 가 증가 하 는 보폭 을 뚜렷하게 알 수 있다.특히 주의해 야 할 것 은 넘 치 는 줄 입 니 다.한 페이지 에 최소 2 줄 의 데 이 터 를 포함 하고 있 습 니 다.페이지 에 저 장 된 줄 이 많 을 수록 성능 이 좋 습 니 다.
************************************
************************************
목적 2:
표 공간 에 데 이 터 를 어떻게 저장 하 는 지,그리고 NULL 값 에 대한 저장 을 알 아 봅 니 다.
테스트 2:
테스트 전에 INNODB 의 저장 형식 부터 알 아 보기(rowformat)。오래된 형식(Antelope):컴 팩 트<기본 값>,Redumdant;새 형식(Barracuda):Compressed,Dynamic.
기본 저장 형식 에 대한 포인터 테스트 입 니 다.
Compact 행 기록 방식 은 다음 과 같 습 니 다.

 |        (1~2  )|NULL   (1  )|     (5  )|RowID(6  )|  ID(6  )|    (7  )|
위의 정 보 는'NULL 플래그 비트'를 제외 하고[표 의 모든 필드 를 NOT NULL 로 정의 합 니 다],'RowID'[표 에 메 인 키 가 있 습 니 다],'길 어 지 는 필드 길이 목록'[길 어 지 는 필드 없 음]이 존재 하지 않 을 수도 있 고 다른 정보 가 나타 납 니 다.따라서 한 줄 의 데 이 터 는 열 데이터 가 차지 하 는 필드 를 제외 하고 18 바이트 가 추가 로 필요 합 니 다.
1:필드 전체 NULL

mysql> create table mytest(t1 varchar(10),t2 varchar(10),t3 varchar(10) ,t4 varchar(10))engine=innodb charset = latin1 row_format=compact;
Query OK, 0 rows affected (0.08 sec)

mysql> insert into mytest values('a','bb','bb','ccc');
Query OK, 1 row affected (0.02 sec)

mysql> insert into mytest values('a','ee','ee','fff');
Query OK, 1 row affected (0.01 sec)

mysql> insert into mytest values('a',NULL,NULL,'fff');
Query OK, 1 row affected (0.00 sec)
테스트 데이터 준비 후 셸 명령 실행:

root@zhoujy:/usr/local/mysql/test# hexdump -C -v mytest.ibd > /home/zhoujy/mytest.txt
my test.txt 파일 을 열 어 supremum 줄 을 찾 습 니 다:

0000c070 73 75 70 72 65 6d 75 6d 03 02 02 01 00 00 00 10 |supremum........| ----------->  ,16  
0000c080 00 25 00 00 00 03 b9 00 00 00 00 02 49 01 82 00 |.%..........I...|
0000c090 00 01 4a 01 10 61 62 62 62 62 63 63 63 03 02 02 |..J..abbbbccc...|
0000c0a0 01 00 00 00 18 00 23 00 00 00 03 b9 01 00 00 00 |......#.........|
0000c0b0 02 49 02 83 00 00 01 4b 01 10 61 65 65 65 65 66 |.I.....K..aeeeef|
0000c0c0 66 66 03 01 06 00 00 20 ff a6 00 00 00 03 b9 02 |ff..... ........|
0000c0d0 00 00 00 02 49 03 84 00 00 01 4c 01 10 61 66 66 |....I.....L..aff|
0000c0e0 66 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |f...............|
설명:
첫 번 째 줄 데이터:
03 02 02 01/*필드 가 길 어 집 니 다*/-표 의 4 개의 필드 유형 은 varchar 이 고 NULL 데이터 가 없 으 며 각 필드 군 은 255 보다 작 습 니 다.
00/*NULL 표지 위치,첫 줄 에 null 데이터 가 없습니다*/
00 00 10 00 25/*헤드 정보 기록,5 바이트 고정*/
00 00 00 03 b9 00/*RowID,6 바이트 고정,표 에 홈 키 없 음*/
00 00 00 02 49 01/*사무 ID,6 바이트 고정*/
82 00 00 01 4a 01 10/*스크롤 백 포인터,7 바이트 고정*/
61 62 62 62 63 63 63/*열의 데이터*/
두 번 째 줄 데 이 터 는 첫 번 째 줄 데이터 와 같 습 니 다(색상 일치).
세 번 째 줄 데이터(NULL 값 이 있 음)와 첫 번 째 줄 의 설명 색상 이 대응 하 는 차이 점:

03 02 02 01 VS 03 01 ----------   NULL ,              。
61 62 62 62 62 63 63 63 VS 61 66 66 66 --------- NULL     ,    
결론:NULL 일 때 필드 목록 이 길 어 지면 저장 공간 을 차지 하지 않 습 니 다.NULL 값 은 저장 되 지 않 고 공간 을 차지 하지 않 지만 표지 위치(한 줄 한 줄)가 필요 합 니 다.
2:필드 전체 NOT NULL

mysql> create table mytest(t1 varchar(10) NOT NULL,t2 varchar(10) NOT NULL,t3 varchar(10) NOT NULL,t4 varchar(10) NOT NULL)engine=innodb charset = latin1 row_format=compact;
Query OK, 0 rows affected (0.03 sec)

mysql> insert into mytest values('a','bb','bb','ccc');
Query OK, 1 row affected (0.01 sec)

mysql> insert into mytest values('a','ee','ee','fff');
Query OK, 1 row affected (0.01 sec)

mysql> insert into mytest values('a',NULL,NULL,'fff');
ERROR 1048 (23000): Column 't2' cannot be null
절차 가 위 와 마찬가지 로 얻 은 ibd 의 결 과 는:

0000c070 73 75 70 72 65 6d 75 6d 03 02 02 01 00 00 10 00 |supremum........|
0000c080 24 00 00 00 03 b9 03 00 00 00 02 49 07 87 00 00 |$..........I....|
0000c090 01 4f 01 10 61 62 62 62 62 63 63 63 03 02 02 01 |.O..abbbbccc....|
0000c0a0 00 00 18 ff cb 00 00 00 03 b9 04 00 00 00 02 49 |...............I|
0000c0b0 08 88 00 00 01 50 01 10 61 65 65 65 65 66 66 66 |.....P..aeeeefff|
위 와 비교 해 보면 NULL 의 표지 위치 정보 가 빠 진 것 을 발견 했다.
결론:NULL 값 은 줄 당 1 바이트 의 크기 를 저장 할 수 있 는 추가 공간 이 있 습 니 다.같은 데이터 의 표 에 대해 필드 에 NULL 값 이 있 는 표 는 NOT NULL 보다 큽 니 다.
3:1 개의 NULL 과 1 개의 데이터:

mysql> create table mytest(t1 varchar(10) NOT NULL,t2 varchar(10) NOT NULL DEFAULT '',t3 varchar(10) NOT NULL ,t4 varchar(10))engine=innodb charset = latin1 row_format=compact;
Query OK, 0 rows affected (0.02 sec)
mysql> insert into mytest(t1,t2) values('A','BB');
Query OK, 1 row affected, 1 warning (0.01 sec)
절차 가 위 와 마찬가지 로 얻 은 ibd 의 결 과 는:

0000c070 73 75 70 72 65 6d 75 6d 00 02 01 01 00 00 10 ff |supremum........|
0000c080 ef 00 00 00 43 b9 03 00 00 00 02 4a 15 90 00 00 |....C......J....|
0000c090 01 c2 01 10 41 42 42 00 00 00 00 00 00 00 00 00 |....ABB.........|
위의 두 가지 차이 점 은 주로 길 어 지 는 목록 과 열 데이터 에 있 습 니 다.
결론:열 데이터 정보 에서 NULL 데이터 와'데 이 터 는 그 어떠한 공간 도 차지 하지 않 는 다 는 것 을 나타 낸다.길 어 지 는 필드 목록 에 대한 정 보 는'데 이 터 는 그 어떠한 저장 공간 도 차지 할 필요 가 없 지만 길 어 지 는 필드 목록 에서 한 글자 절 을 차지 해 야 한다'는 것 과 비교 해 보면 NULL 값 은 차지 할 필요 가 없다'는 것 을 알 수 있다.다만 NULL 은 추가 로 표 시 된 위치 가 있 기 때문에 최적화 설 이 있 습 니 다."데이터베이스 시트 에 NOT NULL 을 설정 할 수 있 는 것 은 가능 한 한 NOT NULL 로 설정 합 니 다.NULL 이 필요 하지 않 는 한"여기 서 증 명 됐 습 니 다.
위의 테스트 는 모두 VARCHAR 의 길 어 지 는 유형 을 겨냥 한 것 인 데 CHAR 에 대해 서 는?
CHAR 테스트:

root@localhost : test 10:33:35>create table mytest(t1 char(10),t2 char(10),t3 char(10) ,t4 char(10))engine=innodb charset = latin1 row_format=compact;Query OK, 0 rows affected (0.16 sec)

root@localhost : test 10:33:59>insert into mytest values('a','bb','bb','ccc');
Query OK, 1 row affected (0.00 sec)

root@localhost : test 10:34:09>insert into mytest values('a','ee','ee','fff');
Query OK, 1 row affected (0.00 sec)

root@localhost : test 10:34:19>insert into mytest values('a',NULL,NULL,'fff');
Query OK, 1 row affected (0.00 sec)
ibd 에서 생 성 된 파일 열기:

0000c060 02 00 1b 69 6e 66 69 6d 75 6d 00 04 00 0b 00 00 |...infimum......|
0000c070 73 75 70 72 65 6d 75 6d 00 00 00 10 00 41 00 00 |supremum.....A..|
0000c080 00 0a f5 00 00 00 00 81 2d 07 80 00 00 00 32 01 |........-.....2.|
0000c090 10 61 20 20 20 20 20 20 20 20 20 62 62 20 20 20 |.a   bb |
0000c0a0 20 20 20 20 20 62 62 20 20 20 20 20 20 20 20 63 |  bb  c|
0000c0b0 63 63 20 20 20 20 20 20 20 00 00 00 18 00 41 00 |cc  .....A.|
0000c0c0 00 00 0a f5 01 00 00 00 81 2d 08 80 00 00 00 32 |.........-.....2|
0000c0d0 01 10 61 20 20 20 20 20 20 20 20 20 65 65 20 20 |..a   ee |
0000c0e0 20 20 20 20 20 20 65 65 20 20 20 20 20 20 20 20 |  ee  |
0000c0f0 66 66 66 20 20 20 20 20 20 20 06 00 00 20 ff 70 |fff  ... .p|
0000c100 00 00 00 0a f5 02 00 00 00 81 2d 09 80 00 00 00 |..........-.....|
0000c110 32 01 10 61 20 20 20 20 20 20 20 20 20 66 66 66 |2..a   fff|
0000c120 20 20 20 20 20 20 20 00 00 00 00 00 00 00 00 00 |  .........|
1 의 varchar 와 비교 해 보면 길 어 지 는 필드 목록 이 적 지만 char 에 게 는 고정 길이 로 저장 해 야 하 며 고정 길이 가 저장 되 지 않 아 도 채 워 집 니 다.예:20;그리고 NULL 값 도 저장 공간 을 차지 할 필요 가 없습니다.
혼합(varchar,char):

root@localhost : test 11:21:48>create table mytest(t1 int,t2 char(10),t3 varchar(10) ,t4 char(10))engine=innodb charset = latin1 row_format=compact;
Query OK, 0 rows affected (0.17 sec)

root@localhost : test 11:21:50>insert into mytest values(1,'a','b','c');
Query OK, 1 row affected (0.00 sec)

root@localhost : test 11:22:06>insert into mytest values(11,'aa','bb','cc');
Query OK, 1 row affected (0.00 sec)
위의 표 구조 에서 볼 수 있다.
1,길 어 지 는 필드 목록 길이:1
2,NULL 표지 위치:1
3,기록 헤더 정보:5
4,RowID:6
5,사무 ID:6
6,스크롤 백 포인터:7
idb 의 정보:

0000c070 73 75 70 72 65 6d 75 6d 01 00 00 00 10 00 33 00 |supremum......3.| 
0000c080 00 00 0a f5 07 00 00 00 81 2d 1a 80 00 00 00 32 |.........-.....2|
0000c090 01 10 80 00 00 01 61 20 20 20 20 20 20 20 20 20 |......a   |
0000c0a0 62 63 20 20 20 20 20 20 20 20 20 02 00 00 00 18 |bc   .....|
0000c0b0 ff be 00 00 00 0a f5 08 00 00 00 81 2d 1b 80 00 |............-...|
0000c0c0 00 00 32 01 10 80 00 00 0b 61 61 20 20 20 20 20 |..2......aa  |
0000c0d0 20 20 20 62 62 63 63 20 20 20 20 20 20 20 20 00 | bbcc  .|
위의 정 보 를 통 해 알 수 있 듯 이 표 에 varchar 필드 가 하나 밖 에 없 기 때문에 목록 길이 가 길 어 지 는 것 은:01 입 니 다.
특히 주의해 야 할 것 은 각 열 데이터 에 저 장 된 정보:t1 필드 는 int 형식 으로 4 개의 바이트 크기 를 차지한다.첫 번 째 줄:8000 00 01 은 1 숫자 를 나타 낸다.두 번 째 줄:8000 00 0b 는 11 의 숫자 를 나타 낸다.select hex(11)=B],다른 것 은 위의 예 와 같 습 니 다.
위 에 있 는 것 은 모두 latin 1 단일 바이트 문자 집합 에 대한 설명 입 니 다.그러면 다 중 바이트 문자 집합 에 대한 상황 은 어 떻 습 니까?

root@localhost : test 11:52:10>create table mytest(id int auto_increment,t2 varchar(10),t3 varchar(10) ,t4 char(10),primary key(id))engine=innodb charset = utf8 row_format=compact;
Query OK, 0 rows affected (0.17 sec)

root@localhost : test 11:52:11>insert into mytest(t2,t3,t4) values('bb','bb','ccc');
Query OK, 1 row affected (0.00 sec)

root@localhost : test 11:55:34>insert into mytest(t2,t3,t4) values('  ','  ','   ');
Query OK, 1 row affected (0.00 sec)
ibd 정 보 는 다음 과 같 습 니 다.

0000c070 73 75 70 72 65 6d 75 6d 0a 02 02 00 00 00 10 00 |supremum........|
0000c080 28 80 00 00 01 00 00 00 81 2d 27 80 00 00 00 32 |(........-'....2|
0000c090 01 10 62 62 62 62 63 63 63 20 20 20 20 20 20 20 |..bbbbccc  |
0000c0a0 0a 06 06 00 00 00 18 ff c7 80 00 00 02 00 00 00 |................|
0000c0b0 81 2d 28 80 00 00 00 32 01 10 e6 88 91 e4 bb ac |.-(....2........|
0000c0c0 e4 bb 96 e4 bb ac e6 88 91 e4 bb ac e7 9a 84 20 |............... |
시계 에 메 인 키 가 있어 서 ROWID(6 바이트)가 없어 졌어 요.
특히 주의해 야 할 것 은:길 어 지 는 필드 목록 은 3?표 안에 있 는 varchar 형식의 열 은 두 개 밖 에 없 는데.테스트 결과 에 따 르 면 다 중 바이트 문자 집합 조건 에서 char 형식 은 가 변 길이 의 유형 으로 처리 되 고 그들의 줄 저장 소 는 거의 다 르 지 않 기 때문에 이것 은 길 어 지 는 목록 이 3 입 니 다.utf 8 문자 집합 이기 때문에 세 개의 바이트 를 차지 합 니 다.그래서 한 한자 가 한 페이지 에 세 바이트 의 공간 을 차지 했다("우리":e6 88 91 e4 bb ac).
데이터 열의 정보:
id 열의 1 값 은 8000 01 이 어야 합 니 다.왜 이것 은 00 32 01 10 을 표시 합 니까?그리고 모든 id 는 00 32 01 10 입 니 다.테스트 결과 id 가 홈 키 를 추가 할 때 id 의 4 바이트 길 이 는 모두 00 32 01 10 으로 표 시 된 것 으로 나 타 났 다.그렇지 않 으 면 앞의 예 에서 말 한 것 과 같이 select HEX(X)로 표시 합 니 다.
총괄 2:
위의 테스트 는 모두 COMPACT 저장 형식 을 기반 으로 합 니 다.varchar 든 char 든 NULL 값 은 저장 공간 을 차지 할 필요 가 없습니다.특히 주의해 야 할 것 은 Redumdant 의 기록 헤드 정 보 는 6 개의 고정 바이트 가 필요 하 다 는 것 이다.다 중 바이트 문자 집합의 조건 하에 서 CHAR 와 VARCHAR 의 줄 저장 소 는 기본적으로 차이 가 없다.
이 글 은 MySQL Innodb 저장 구조 와 Null 값 저장 용법 에 대한 상세 한 설명 입 니 다.MySQL Innodb 저장 구조 에 대해 더 많은 것 을 소개 합 니 다.   Null 값 내용 을 저장 하려 면 이전 글 을 검색 하거나 아래 글 을 계속 찾 아 보 세 요.앞으로 도 많은 응원 부 탁 드 리 겠 습 니 다!

좋은 웹페이지 즐겨찾기