Ⅰ. A small test without primary key
1.1 There is a unique key on the table
(root@localhost) [test]> show create table test_key\G
*************************** 1. row ***************************
Table: test_key
Create Table: CREATE TABLE `test_key` (
`a` int(11) DEFAULT NULL,
`b` int(11) NOT NULL,
`c` int(11) NOT NULL,
UNIQUE KEY `b` (`b`),
UNIQUE KEY `c` (`c`),
UNIQUE KEY `a` (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
(root@localhost) [test]> select *, _rowid from test_key;
+------+---+---+--------+
| a | b | c | _rowid |
+------+---+---+--------+
| 1 | 2 | 3 | 2 |
| 4 | 5 | 6 | 5 |
| 7 | 8 | 9 | 8 |
+------+---+---+--------+
3 rows in set (0.00 sec)
可以看出,b列被作为了主键
(root@localhost) [test]> show create table test_key2\G
*************************** 1. row ***************************
Table: test_key2
Create Table: CREATE TABLE `test_key2` (
`a` varchar(4) DEFAULT NULL,
`b` varchar(4) NOT NULL,
`c` varchar(4) NOT NULL,
UNIQUE KEY `b` (`b`),
UNIQUE KEY `c` (`c`),
UNIQUE KEY `a` (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
(root@localhost) [test]> select *, _rowid from test_key2;
ERROR 1054 (42S22): Unknown column '_rowid' in 'field list'
这里_rowid只有当key类型为id时才有效
换俩办法看即可
法1:
(root@localhost) [test]> select * from information_schema.columns where table_name='test_key2' and column_key='pri'\G
*************************** 1. row ***************************
TABLE_CATALOG: def
TABLE_SCHEMA: test
TABLE_NAME: test_key2
COLUMN_NAME: b
ORDINAL_POSITION: 2
COLUMN_DEFAULT: NULL
IS_NULLABLE: NO
DATA_TYPE: varchar
CHARACTER_MAXIMUM_LENGTH: 4
CHARACTER_OCTET_LENGTH: 4
NUMERIC_PRECISION: NULL
NUMERIC_SCALE: NULL
DATETIME_PRECISION: NULL
CHARACTER_SET_NAME: latin1
COLLATION_NAME: latin1_swedish_ci
COLUMN_TYPE: varchar(4)
COLUMN_KEY: PRI
EXTRA:
PRIVILEGES: select,insert,update,references
COLUMN_COMMENT:
GENERATION_EXPRESSION:
1 row in set (0.00 sec)
法2:
(root@localhost) [test]> desc test_key2;
+-------+------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------+------+-----+---------+-------+
| a | varchar(4) | YES | UNI | NULL | |
| b | varchar(4) | NO | PRI | NULL | |
| c | varchar(4) | NO | UNI | NULL | |
+-------+------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
看到b列被作为主键
1.2 No unique key on the table
When the primary key is not explicitly specified in the table, and there is no non-null unique key, the system will customize a primary key (6 bytes, int, global, hidden)
(root@localhost) [test]> show create table test_key3\G
*************************** 1. row ***************************
Table: test_key3
Create Table: CREATE TABLE `test_key3` (
`a` int(11) DEFAULT NULL,
`b` int(11) DEFAULT NULL,
`c` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
(root@localhost) [test]> select * from test_key3;
+------+------+------+
| a | b | c |
+------+------+------+
| 1 | 2 | 3 |
| 4 | 5 | 6 |
| 7 | 8 | 9 |
+------+------+------+
3 rows in set (0.00 sec)
(root@localhost) [test]> select *, _rowid from test_key3;
ERROR 1054 (42S22): Unknown column '_rowid' in 'field list'
(root@localhost) [test]> select * from information_schema.columns where table_name='test_key3' and column_key='pri'\G
Empty set (0.00 sec)
(root@localhost) [test]> desc test_key3;
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| a | int(11) | YES | | NULL | |
| b | int(11) | YES | | NULL | |
| c | int(11) | YES | | NULL | |
+-------+---------+------+-----+---------+-------+
3 rows in set (0.00 sec)
由上可见,这种情况下_rowid我们是看不了的,对我们透明
tips:
Assuming that there are two tables using the system-defined primary key, the id of the system-defined primary key is not monotonically increasing in the table, but increasing globally.
The rowid of the system is defined in sys_rowid in ibdata1.ibd, which is incremented globally.
The amount of data represented by 6 bytes is 2^48, which is usually enough
It is strongly recommended that you must explicitly define the primary key yourself
Ⅱ. The structure of the page
One Page |
---|
File Header |
Page Header |
Infimun + Supermum Records |
User Records |
Free Space |
Page Directory |
File Trailer |
- The size of the file header, page header, and file end information is fixed at 38, 56, and 8 bytes. These information are used to record some information about the page, such as its location in the b+ tree, checksum, etc.
- User record, free space, page directory is the actual row record storage space, the size is not fixed
- Infimun + Supermum Records record two virtual records, one minimum and one maximum
- A page can store up to 16k/2 - 200 rows of records, that is, 7992 rows
2.1 File Header
- | number of bytes | Remark |
---|---|---|
FIL_PAGE_SPACE_OR_CHKSUM | 4 | It was 0 before 4.0.14, now it is the checksum value of the page |
Fil_PAGE_OFFSET | 4 | The offset position of the page, which is used to locate the position of the page in a table space |
FIL_PAGE_PREV | 4 | Previous |
FIL_PAGE_NEXT | 4 | next page |
FIL_PAGE_LSN | 8 | The LSN of the last modified page ui |
FIL_PAGE_TYPE | 2 | The type of the page (0x45BF indicates that the data page is stored) |
FIL_PAGE_FILE_FLUSH_LSN | 8 | There is only one page defined in the system tablespace, indicating that the file has been updated to at least the LSN, and the value in the independent tablespace is 0 |
FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID | 4 | 4.1 Beginning with this value indicating which space the page belongs to |
Types of pages in InnoDB:
B+ tree page, Undo Log page, inode, system page, newly allocated page, BLOB page, Insert Buffer free list and bitmap, etc.
2.2 Page Header
Record the status information of the data page, which consists of 14 parts, occupying 56 bytes, and will not be analyzed here.
2.3 Infimum and Supermum Record
Represents two virtual records, which are used to limit the boundary of the page. The page is created when it is created and will never be deleted. Different row formats have different sizes.
2.4 User Record 和 Free Space
User Record is the content of the actual storage record. Innodb is always B+ tree index organization
Free Space is free space, which is a linked list structure. When a record is deleted, the space is added to the free linked list.
2.5 Page Directory
The relative position of the record (relative position of the page)
You cannot find a record directly, you can only locate the page where the record is located, drag the page into the memory, and perform a binary search through the Page Directory
2.6 File Trailer
Used to detect whether the page is placed normally
Inside is a FIL_PAGE_END_LSN, occupying 8 bytes, the first 4 bytes represent checksum, and the last 4 bytes are the same as FIL_PAGE_LSN in File Header. Compare these two values with FIL_PAGE_SPACE_OR_CHECKSUM and FIL_PAGE_LSN in File_Header to ensure page integrity (not corrupted) , the comparison needs to be done through the checksum function of innodb, not the equivalent comparison
tips:
Every time a page is read from disk to check the integrity will bring a certain overhead
5.6.6 The parameter innodb_checksum_algorithm can control the algorithm of checksum, the default is crc32, the former is innodb, the former is more efficient
If the pages are saved with the strict algorithm, the lower version of MySQL will not be able to read these pages, and mysql_upgrade is required.
strict_crc32 is the fastest verification method, recommended
Ⅲ. Record
3.1 Format of the record - ROW_FORMAT
Format | illustrate |
---|---|
REDUDENT | Default format before 4.1 |
COMPACT | 5.6 Default format |
COMPRESSED | support compression |
DYNAMIC | 5.7 Default format, optimized for large objects |
3.2 COMPACT structure
variable string length list | NULL flag | record header | col | col2 | ... |
---|---|---|---|---|---|
The column length is less than 255 bytes, represented by 1 byte, otherwise 2 bytes (reverse order) | 1 byte | 5 bytes |
tips:
- Record header information saves information such as whether the row is deleted
- NULL does not account for actual storage
- In addition to the custom column, each row of data has two hidden columns, transaction id (6 bytes) and rollback pointer (7 bytes). If there is no custom primary key, a 6-byte rowid column will be added.
3.2 DYNAMIC
Compared with COMPACT, DYNAMIC optimizes the storage of large object records
Suppose a record has four columns ABCD, and column D in i is of text type, containing a length of 2w bytes
COMPACT will store the first 768 bytes in the text, and the remaining data will point to the overflow page through a 20-byte pointer
DYNAMIC is stored as follows, no prefix data
DYNAMIC stores more records in a page (768 bytes of prefix, assuming 800 bytes for a tune record, that 16k page can only store 20 records), so b+tree may become higher, read The number of io fetches increases, and the performance deteriorates
3.3 Update of records
in place update
- In-place updates do not take up new storage space
- The out-of-place update needs to delete (physically delete) the original space, and then insert the updated data into the back of the page
- The deleted data space will be inserted into the head of the Free_List linked list
- In-place updates do not trigger page splits
Free_List is to concatenate the deleted spaces in the page (to form a linked list). When data is inserted into the page, first look at the size of the first space in the Free_list. If the space is suitable, insert the record into the Go to the first space, if it is not suitable, insert it directly into the remaining space at the end of the page (will not look at the second space of Free_list)
When the data of the page is full, paging will not be performed immediately, but the reorganize operation will be performed, that is, the data in the page will be sorted in memory, and then the original page will be overwritten (without affecting performance), so InnoDB does not need defragmentation.
Reorganize