prefácio
O artigo anterior disse que o InnoDB tem formatos Compact
, Redundant
, Dynamic
e Compressed4
de linha. Ele fala principalmente sobre Compact
o formato de linha, que é composto de duas partes principais: informações adicionais registradas e dados reais gravados. Recomenda-se a leitura do artigo anterior e do artigo anterior .Se for importante Diga [ através do trem ] três vezes, não pule o capítulo. Hoje, entendemos principalmente os três formatos de linha restantes e o estouro de dados de linha
Índice
1. Formato de linha redundante
O formato de linha redundante é um formato de linha usado antes do MySQL 5.0, o que significa que é muito antigo, mas ainda quero mencioná-lo do ponto de vista do aprendizado e todos podem entendê-lo. O formato de linha redundante Como mostrado na figura:
Para um melhor aprendizado, criamos uma demo3
tabela aqui e adicionamos dois dados
mysql> create table demo3( c1 varchar(10), c2 varchar(10) not null, c3 char(10), c4 varchar(10), c5 varchar(1024)) charset=ascii row_format=Redundant;
Query OK, 0 rows affected (0.02 sec)
mysql> insert into demo3 values('aaaaa','bbbb','ccc','dd','e');
Query OK, 1 row affected (0.00 sec)
mysql> insert into demo3 values('eeeee','ffff',null,null,'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdeefghijklmnopqrstuvwxyz');
Query OK, 1 row affected (0.00 sec)
Os registros na tabela agora se parecem com isso
mysql> select * from demo3;
+-------+------+------+------+------------------------------------------------------------------------------------------------------------------------------------+
| c1 | c2 | c3 | c4 | c5 |
+-------+------+------+------+------------------------------------------------------------------------------------------------------------------------------------+
| aaaaa | bbbb | ccc | dd | e |
| eeeee | ffff | NULL | NULL | abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz |
+-------+------+------+------+------------------------------------------------------------------------------------------------------------------------------------+
2 rows in set (0.00 sec)
Vamos dar uma olhada nas diferenças no formato de linha redundante de vários aspectos.
1.1 Lista de compensação de comprimento de campo
Compact
O início do formato de linha é uma lista de comprimento de campo de comprimento variável e Redundant
o início do formato de linha é uma lista de deslocamento de comprimento de campo, que é diferente da lista de comprimento de campo de comprimento variável de duas maneiras:
- Não há
变长
duas palavras, ou seja, o formato de linha redundante armazenará as informações de comprimento de todas as colunas (incluindo colunas ocultas) no registro em ordem inversa à lista de deslocamento de comprimento de campo - Existem mais duas
偏移
palavras, o que significa que o método de cálculo do comprimento é diferente do formato de linha Compact, que não é tão intuitivo, pois usa a diferença entre números adjacentes para calcular o comprimento de cada coluna.
Por exemplo, a primeira linha de dados, vamos tentar analisá-la:
O comprimento da primeira coluna row_id
é de 6 bytes, ou seja, o comprimento da 0x06
segunda coluna trx_id
é de 6 bytes, totalizando 12 bytes, ou seja, o comprimento da 0x0c
terceira coluna roll_pointer
é de 7 bytes, totalizando 19 bytes, também Isso ou seja, o comprimento da 0x13
quarta coluna C1
é de 5 bytes, um total de 24 bytes, ou seja, o comprimento da 0x18
quinta coluna C2
é de 4 bytes, um total de 28 bytes, ou seja, o comprimento 0x1c
da sexta coluna C3
é de 10 bytes, Um total de 38 bytes, ou seja, o comprimento 0x26
da sétima coluna C4
é de 2 bytes, um total de 40 bytes, ou seja, o comprimento 0x28
da oitava coluna C5
é de 1 byte, um total de 41 bytes, ou seja0x29
O efeito da descarga de ordem inversa é: 29 28 26 1c 18 13 0c 06
, preencha os dados conforme mostrado na figura
Abrimos diretamente demo3.ibd
o arquivo para visualizar
1.2 Informações do cabeçalho do registro
As informações do cabeçalho do registro no formato de linha redundante consistem em 6 bytes e 48 bits binários. Os significados desses bits binários são os seguintes:
nome | tamanho (unidade: bit) | descrever |
---|---|---|
Bit reservado 1 | 1 | não usado |
Reservado 2 | 1 | não usado |
delete_mask | 1 | Marque se o registro foi deletado |
min_rec_mask | 1 | Esta marca será adicionada ao menor registro em cada nó não folha da árvore B+ |
n_propriedade | 4 | Indica o número de registros pertencentes ao registro atual |
heap_no | 13 | Indica as informações de posição do registro atual na pilha de registros |
n_campo | 10 | Indica o número de colunas no registro |
1byte_offs_flag | 1 | Se o deslocamento correspondente a cada coluna na lista de deslocamento do comprimento do campo de tag é representado por 1 byte ou 2 bytes |
próximo_registro | 16 | Indica a posição relativa do próximo registro |
A primeira linha de informações do cabeçalho do registro é:00 00 10 11 00 ca
Vamos converter o registro acima de hexadecimal para binário e tentar analisá-lo
00000000 00000000 00010000 00010001 00000000 11001010
De acordo com esses dados binários, as seguintes informações podem ser obtidas dividindo os dados de acordo com a estrutura do cabeçalho do registro
Bit reservado 1: 0
Bit reservado 2: 0
delete_mask: 0
min_rec_mask: 0
n_owned: 0000
heap_no: 00000000 00010 (2)
n_field: 000 0001000 (8)
1byte_offs_flag: 1 (1)
next_record: 00000000 11001010 ( 202)
Em comparação com as informações do cabeçalho do registro no formato de linha Compacto, há duas diferenças:
- O formato de linha redundante possui mais dois atributos: n_field e 1byte_offs_flag;
- O formato de linha redundante não possui o atributo record_type.
1.4 Como escolher o valor de 1byte_offs_flag
Dissemos anteriormente que o deslocamento correspondente a cada coluna pode ocupar 1 byte ou 2 bytes para armazenamento, então quando usar 1 byte e quando usar 2 bytes? Na verdade, é julgado de acordo com o tamanho total dos dados reais registrados no formato de linha redundante:
-
Quando o número de bytes ocupados pelos dados reais gravados for menor ou igual a 127 (hexadecimal 0x7f, binário 01111111), o deslocamento correspondente a cada coluna ocupa 1 byte
-
Quando o número de bytes ocupados pelos dados reais registrados for maior que 127, mas não maior que 32767 (hexadecimal 0x7fff, binário 01111111111111111), o deslocamento correspondente a cada coluna ocupa 2 bytes
-
Quando os dados reais do registro são maiores que 32767, o registro neste momento foi armazenado na página de estouro, e apenas os primeiros 768 bytes e o endereço da página de estouro de 20 bytes são reservados nesta página (é claro, nesses 20 bytes Algumas outras informações também são registradas). Como a lista de deslocamento do comprimento do campo só precisa registrar o deslocamento de cada coluna nesta página, é suficiente que cada coluna use 2 bytes para armazenar o deslocamento.
Para saber se o deslocamento de cada coluna é representado por 1 byte ou 2 bytes ao analisar registros, o formato de linha redundante coloca deliberadamente um atributo chamado 1byte_offs_flag nas informações do cabeçalho do registro:
- Quando seu valor é 1, indica que 1 byte é usado para armazenamento
- Quando seu valor é 0, indica que 2 bytes são usados para armazenamento
1.5 Tratamento de valores NULL no formato de linha redundante
Como o formato de linha redundante não possui uma lista de valores NULL, o formato de linha redundante faz algum processamento especial nos deslocamentos correspondentes a cada coluna na lista de deslocamento de comprimento de campo - o primeiro bit do valor de deslocamento correspondente à coluna Como base pois se for NULL, esse bit também pode ser chamado de bit NULL. Ou seja, ao analisar uma coluna de um registro, verifique primeiro se o bit NULL do deslocamento correspondente à coluna é 1, se for 1, o valor da coluna é NULL, caso contrário, não é NULL.
Isso também explica porque, desde que os dados reais registrados acima sejam maiores que 127 (hexadecimal 0x7f, binário 01111111), 2 bytes são usados para representar o deslocamento correspondente a uma coluna, principalmente o primeiro bit É o chamado bit NULL, usado para marcar se o valor da coluna é NULL.
Mas há outro ponto a observar, para uma coluna com um valor NULL, se o tipo da coluna é um tipo de comprimento fixo determina o método de armazenamento real do valor NULL:
- Se o campo que armazena o valor NULL for do tipo de comprimento fixo, como o tipo de dados CHAR(M), o valor NULL também ocupará a parte de dados reais do registro e os dados correspondentes a esse campo serão preenchidos com 0x00 bytes .
- Se o campo que armazena o valor NULL for do tipo de dados de comprimento variável, nenhum espaço de armazenamento será ocupado nos dados reais do registro.
Além dos pontos acima, o formato de linha redundante e o formato de linha compacta são aproximadamente os mesmos
Vamos tentar analisar o segundo dado (o número de bytes ocupados pelos dados reais é maior que 127):
O comprimento da primeira coluna row_id
é de 6 bytes, ou seja, o comprimento da 0x00 0x06
segunda coluna trx_id
é de 6 bytes, totalizando 12 bytes, ou seja, o comprimento da 0x00 0x0c
terceira coluna roll_pointer
é de 7 bytes, totalizando 19 bytes, também Isso ou seja, o comprimento da 0x00 0x13
quarta coluna C1
é de 5 bytes, um total de 24 bytes, ou seja, o comprimento da 0x00 0x18
quinta coluna C2
é de 4 bytes, um total de 28 bytes, ou seja, o comprimento 0x00 0x1c
da sexta coluna C3
é de 10 bytes, Um total de 38 bytes, ou seja 0x00 0x26
, mas o valor é NULL, 最高位标识1
depois disso, o valor 0x80 0x26
da sétima coluna C4
é NULL, um total de 38 bytes, ou seja, o comprimento da 0x80 0x26
oitava coluna C5
é de 130 bytes, um total de 168 Festival de personagens, ou seja0x00 0xa8
Abrimos diretamente o arquivo demo3.ibd para ver se está correto:
Além dos pontos acima, o formato de linha redundante e o formato de linha compacta são praticamente os mesmos.
1.6 Formato de armazenamento da coluna CHAR(M)
Sabemos que o formato de linha compacta é bastante problemático ao armazenar dados em colunas do tipo CHAR(M). Ele é dividido em conjuntos de caracteres de comprimento variável e conjuntos de caracteres de comprimento fixo, mas é muito simples no formato de linha redundante, independentemente os caracteres usados na coluna. Qual é o conjunto, desde que o tipo CHAR(M) seja usado, o espaço de dados real ocupado é o produto do número máximo de bytes exigidos pelo conjunto de caracteres para representar um caractere e M. Por exemplo, o espaço de dados real ocupado por uma coluna do tipo CHAR(10) usando o conjunto de caracteres utf8 é sempre de 30 bytes, e o espaço de dados real ocupado por uma coluna do tipo CHAR(10) usando o conjunto de caracteres gbk é sempre de 20 bytes. Pode-se ver a partir disso que a coluna do tipo CHAR(M) usando o formato de linha redundante não gerará fragmentação.
2. Estouro de dados de linha
2.1 O máximo de dados que VARCHAR(M) pode armazenar
Sabemos que uma coluna do tipo VARCHAR(M) pode ocupar até 65535 bytes. Entre eles, M representa o número máximo de caracteres armazenados neste tipo. Se usarmos o conjunto de caracteres ASCII, um caractere representa um byte. Vamos ver se VARCHAR(65535) está disponível
mysql> create table demo4 (c varchar(65535)) charset=ascii row_format=compact;
ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs
Pode ser visto na mensagem de erro que o MySQL tem um limite no espaço máximo de armazenamento ocupado por um registro. Exceto para colunas do tipo BLOB ou TEXT, os bytes ocupados por todas as outras colunas (excluindo colunas ocultas e informações de cabeçalho de registro) O total comprimento não pode exceder 65535 bytes. Portanto, o servidor MySQL sugere que alteremos o tipo de armazenamento para o tipo TEXT ou BLOB. Além dos dados da própria coluna, esses 65535 bytes também incluem alguns outros dados (sobrecarga de armazenamento). Por exemplo, para armazenar uma coluna do tipo VARCHAR(M), na verdade precisamos ocupar 3 partes do espaço de armazenamento:
- dados reais
- Os dados reais ocupam o comprimento do byte (podem ocupar dois bits)
- Identificação do valor NULL, se a coluna não tiver o atributo NOT NULL (um bit), então apenas 65532 bytes de dados podem ser armazenados no máximo
mysql> create table demo4 (c varchar(65532)) charset=ascii row_format=compact;
Query OK, 0 rows affected (0.06 sec)
Se a coluna do tipo VARCHAR(M) não usar o conjunto de caracteres ASCII, o valor máximo de M dependerá do número máximo de bytes exigidos pelo conjunto de caracteres para representar um caractere. No caso em que o valor da coluna pode ser NULL, o conjunto de caracteres gbk indica que um caractere requer no máximo 2 bytes; nesse conjunto de caracteres, o valor máximo de M é 32766 (ou seja: 65532/2) , ou seja, pode armazenar até 32766 caracteres; o conjunto de caracteres utf8 significa que um caractere precisa de até 3 bytes; portanto, nesse conjunto de caracteres, o valor máximo de M é 21844, o que significa que ele pode armazenar até 21844 ( ou seja: 65532/3) caractere.
2.2 Estouro causado por excesso de dados no registro
Vamos fazer um teste com ascii
uma demo4
tabela de conjunto de caracteres e inserir um dado:
mysql> insert into demo4 values(repeat('a',65532));
Query OK, 1 row affected (0.02 sec)
Dica:
REPEAT('a', 65532) é uma chamada de função, que significa gerar uma string que repete o caractere 'a' 65532 vezes
Como mencionado anteriormente, a unidade básica de interação entre disco e memória no MySQL é a página, ou seja, o MySQL usa a página como unidade básica para gerenciar o espaço de armazenamento, e nossos registros serão alocados para uma determinada página para armazenamento. O tamanho de uma página é geralmente 16 KB, que é 16384 bytes, e um VARCHAR(M)
tipo de coluna pode armazenar até 65532 bytes, o que pode causar uma situação embaraçosa em que uma página não pode armazenar um registro
Nos formatos de linha Compacto e Reduntante, para uma coluna que ocupa um grande espaço de armazenamento, apenas uma parte dos dados da coluna será armazenada nos dados reais do registro, e os dados restantes serão dispersos e armazenados em vários outros páginas e, em seguida, os dados reais do registro O local de dados usa 20 bytes para armazenar os endereços que apontam para essas páginas (claro, esses 20 bytes também incluem o número de bytes ocupados pelos dados espalhados em outras páginas), para que o pode ser encontrada a página onde os dados restantes estão localizados, como mostrado na figura:
Como pode ser visto na figura, para os formatos de linha Compact e Reduntant, se houver muitos dados em uma coluna, apenas os primeiros 768 bytes de dados na coluna e um ponteiro para outras colunas serão armazenados nos dados reais de este registro. O endereço da página e, em seguida, armazenar os dados restantes em outras páginas. Esse processo também é chamado de estouro de página, e as páginas que armazenam mais de 768 bytes também são chamadas de páginas de estouro.
Finalmente, deve-se notar que não apenas colunas do tipo VARCHAR(M), mas também colunas de outros tipos TEXT e BLOB irão estourar ao armazenar muitos dados.
Três, o ponto crítico de estouro de linha
Qual é o ponto crítico onde ocorre o estouro de linha? Em outras palavras, estouro de linha ocorre quando a coluna armazena quantos bytes de dados?
O MySQL estipula que pelo menos duas linhas de registros devem ser armazenadas em uma página. Além de armazenar nossos registros, cada página também precisa armazenar algumas informações adicionais. As informações extras confusas precisam adicionar até 132 bytes de espaço (agora você só precisa saber este número. ok), o restante do espaço pode ser usado para armazenar registros.
A informação adicional necessária para cada registro é de 27 bytes.
- 2 bytes são usados para armazenar o comprimento dos dados reais
- 1 byte é usado para armazenar se a coluna é um valor NULL
- 5 bytes de informações de cabeçalho
- 6 bytes para a coluna DB_ROW_ID
- 6 bytes para a coluna DB_TRX_ID
- 7 bytes para a coluna DB_ROLL_PTR
Assumindo que o número de bytes de dados armazenados em uma coluna é n, o MySQL estipula que, se a coluna não estourar, ela precisa satisfazer a seguinte fórmula:
132 + 2×(27 + n) < 16384
Resolver esta fórmula leva à solução: n <8099. Ou seja, se os dados armazenados em uma coluna forem menores que 8099 bytes, a coluna não se tornará uma coluna de estouro, caso contrário, a coluna precisará se tornar uma coluna de estouro. No entanto, a conclusão de 8099 bytes é apenas para uma demo4
tabela com apenas uma coluna. Se houver várias colunas na tabela, a fórmula e a conclusão acima precisam ser alteradas, então o ponto é: você não precisa prestar atenção isso crítico Qual é o ponto, apenas saiba que se os dados armazenados em uma coluna do nosso registro ocuparem muitos bytes, a coluna pode se tornar uma coluna de estouro.
Formato de linha quatro, DINÂMICO e COMPRIMIDO
O seguinte apresentará os outros dois formatos de linha Dynamic
e Compressed
o formato de linha. A versão do MySQL que estou usando agora é 8.0 e seu formato de linha padrão é Dinâmico
mysql> show variables like '%innodb_default_row_format%';
+---------------------------+---------+
| Variable_name | Value |
+---------------------------+---------+
| innodb_default_row_format | dynamic |
+---------------------------+---------+
1 row in set (0.04 sec)
mysql> set persist innodb_default_row_format = 'dynamic';
Query OK, 0 rows affected (0.01 sec)
Esses dois formatos de linha são semelhantes ao formato de linha Compact, mas são um pouco diferentes ao lidar com dados de estouro de linha. Eles não armazenarão os primeiros 768 bytes dos dados reais do campo nos dados reais do registro, mas armazenarão todos os bytes Eles são todos armazenados em outras páginas, e apenas os endereços de outras páginas são armazenados nos dados reais registrados.
A diferença entre o formato de linha compactado e dinâmico é que o formato de linha compactado usa um algoritmo de compactação para compactar a página para economizar espaço.
Resumir
Esses dois artigos tem muito conhecimento teórico, haha, mas felizmente não são muito usados no trabalho. É bom que todos conheçam esses termos, pois na explicação do MVCC mais adiante, também usaremos alguns termos profissionais neste artigo . InnoDB define 4 formatos de linha, e a estrutura de registro de cada formato de linha é diferente. Ao mesmo tempo, também aprendemos sobre os métodos de armazenamento de tipos de dados de comprimento fixo e variável na estrutura de registro e estouro de linha. Vamos lá. concluir
-
A página é a unidade básica de interação de disco e memória no MySQL e também a unidade básica do MySQL para gerenciar o espaço de armazenamento.
-
InnoDB atualmente define 4 formatos de linha:
- Formato de linha COMPACTO:
- Formato de linha REDUNDANTE:
-
Formatos de linha DYNAMIC e COMPRESSED:
Os formatos de linha Dinâmico e Compactado são semelhantes ao formato de linha COMPACT, e são um pouco diferentes ao lidar com dados de estouro de linha. Eles não armazenam os primeiros 768 bytes dos dados reais do campo nos dados reais do registro, mas armazenam todos os bytes. Para outras páginas, apenas armazene o endereço de outras páginas nos dados reais do registro
- Formato de linha COMPACTO:
-
Formato de linha COMPACT Para colunas do tipo CHAR(M), quando a coluna usa um conjunto de caracteres de comprimento fixo, o número de bytes ocupados pela coluna não será adicionado à lista de comprimento de campo de comprimento variável e, se o comprimento variável conjunto de caracteres for usado, o número de bytes ocupados pela coluna também será adicionado à lista de comprimento de campo de comprimento variável.
-
No caso em que o valor da coluna pode ser NULL, o valor máximo de M no conjunto de caracteres gbk é 32766 e o valor máximo de M no conjunto de caracteres utf8 é 21844. Isso tudo no caso de apenas um campo na tabela. Certifique-se de lembrar que o comprimento total de bytes ocupados por todas as colunas em uma linha (excluindo colunas ocultas e informações de cabeçalho de registro) não pode exceder 65535 bytes!
-
Quando há muitos dados no registro e não cabem na página atual, os dados excedentes serão armazenados em outras páginas, fenômeno chamado estouro de linha. Nos formatos de linha Compacto e Redundante, para colunas que ocupam um grande espaço de armazenamento, apenas uma parte dos dados da coluna será armazenada nos dados reais gravados, e os dados restantes serão dispersos e armazenados em várias outras páginas, e então os 20 bytes de dados reais registrados são usados para armazenar endereços que apontam para essas páginas.
-
O ponto crítico do estouro de linha: se os dados armazenados em uma coluna forem menores que 8.099 bytes, a coluna não se tornará uma coluna de estouro, caso contrário, a coluna precisa ser uma coluna de estouro. No entanto, a conclusão de 8099 bytes é apenas para uma tabela com apenas uma coluna. Se houver várias colunas na tabela, a conclusão será inconsistente, então a questão é: você não precisa prestar atenção em qual é o ponto crítico ou seja, apenas saiba que se quando os dados armazenados em uma coluna de um registro ocuparem um número muito alto de bytes, a coluna pode se tornar uma coluna de estouro.
-
As colunas do tipo CHAR(M) do conjunto de caracteres de comprimento variável requerem pelo menos M bytes, enquanto VARCHAR(M) não possui esse requisito. Por exemplo, para uma coluna CHAR(10) usando o conjunto de caracteres utf8, o comprimento dos dados armazenados na coluna varia de 10 a 30 bytes. Mesmo se armazenarmos uma string vazia nesta coluna, ela ocupará 10 bytes. Isso ocorre porque o comprimento de bytes do valor atualizado no futuro é maior que o comprimento de bytes do valor original e menor que 10 bytes. O registro é atualizado diretamente em vez de realocar um novo espaço de registro no espaço de armazenamento, fazendo com que o espaço de registro original se torne a chamada fragmentação
Quando terminei de aprender essa parte do conhecimento, admirei a profundidade da pesquisa do autor.Embora os pontos de conhecimento sejam muitos, difíceis e complicados, a forma como o autor combina imagens e textos nos permite entendê-lo bem.
Até agora, o estudo de hoje acabou, espero que você se torne um eu indestrutível
~~~
Você não pode ligar os pontos olhando para frente; você só pode conectá-los olhando para trás. Portanto, você precisa confiar que os pontos de alguma forma se conectarão em seu futuro. Você precisa confiar em algo - seu instinto, destino, vida, karma, seja o que for. Essa abordagem nunca me decepcionou e fez toda a diferença na minha vida
Se meu conteúdo for útil para você, por favor 点赞
, criar não é fácil, o apoio de todos é a 评论
motivação 收藏
para eu perseverar